Skip to content

Wire voter-limit resolution hierarchy, payment-required response & lock down voter_limit in editElectionController #1585

Description

@ArendPeter

Question / Task

Part of the Phase 1 Payment System: Design & Build Map, graduated from Design backend data model & Stripe integration flow for Phase 1 payments (see that ticket's resolution comment for full design rationale). Blocked by the migration/config ticket (voter_limit column, pricing constants).

Voter-limit resolution (packages/backend/src/Controllers/Roll/addElectionRollController.ts:86-91): replace let voterLimit = overrides[...] ?? sharedConfig.FREE_TIER_PRIVATE_VOTER_LIMIT with overrides[req.election.election_id] ?? req.election.voter_limit. The old free-tier fallback constant is no longer needed — it's baked into voter_limit's initial value.

"Payment required" response: when the limit check fails, throw a response shaped like:

{
  "error": "Request Denied: this election is limited to 100 voters",
  "code": "PAYMENT_REQUIRED",
  "currentVoterLimit": 100,
  "requestedVoterCount": 150,
  "blockSize": 200,
  "pricePerBlockCents": 1000
}

(This repo's errors are currently always a flat {error: string}errorCatchMiddleware.ts — so this is a new, deliberately narrow special case, not a general error-code system.) On the frontend, AddElectionRoll.tsx's submit catch handler should check for code === 'PAYMENT_REQUIRED' and open the payment/cart modal (built in the sibling prototype ticket) instead of just showing the snackbar — this ticket only needs to emit the response shape and do the minimal catch-handler branch; the modal itself is separate frontend work tracked elsewhere on the map.

Lock down voter_limit: packages/backend/src/Controllers/Election/editElectionController.ts currently takes req.body.Election (the entire client-submitted object) and passes it straight to ElectionsModel.updateElection() — verified at editElectionController.ts:15,37. Before calling updateElection(), overwrite inputElection.voter_limit with req.election.voter_limit (the server's current value), discarding whatever the client submitted for that field, so voter_limit can only ever change via the Stripe-driven applyVoterLimitPurchase path (built in the webhook ticket).

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions