This document describes the high-level architecture of ModNVote 2.0 and the design constraints that must be preserved when extending the system.
ModNVote 2.0 is built around four non-negotiable goals:
- Privacy — identity and vote content must not be joinable
- Verifiability — players can verify their participation and/or ballot
- Tamper evidence — changes must be detectable
- Usability — voting must be clear, guided, and intuitive
All architectural decisions must reinforce these goals.
The system is structured into clear layers with strict separation of concerns.
- Parses user input
- Performs permission checks
- Displays formatted output
- Delegates all business logic to services
The command layer must not:
- write directly to the database
- reconstruct ballot logic
- bypass validation rules
- Manages inventory-based voting interfaces
- Tracks player interaction state
- Handles click events and transitions between screens
Key components:
VoteSessionYesNoVoteSessionVoteSessionManagerYesNoVoteSessionManagerJavaInventoryVoteRendererYesNoInventoryVoteRendererVoteGuiListenerYesNoVoteGuiListenerVoteSubmissionCoordinator
Responsibilities:
- Present poll options to the player
- Capture user selections
- Enforce UX rules (confirmation step, slot restrictions)
- Forward final selections to the service layer
The GUI/session layer must not:
- write ballots to the database
- modify poll lifecycle state
The service layer is authoritative.
Key services include:
PollServiceBallotServiceIntegrityVerificationService
Responsibilities:
- Poll lifecycle management (
DRAFT -> READY -> OPEN -> CLOSED) - Validation of poll definitions
- Enforcement of Yes/No semantics
- Ballot submission and validation
- Duplicate prevention
- Result calculation
- Verification logic
All validation must occur here.
- Handles all database interaction
- Encapsulates SQL logic
Key data domains:
- Polls
- Poll options
- Participation records (identity-aware)
- Anonymous ballots (vote content)
- Ballot preferences (ranked ordering)
- Audit events
The system enforces strict separation between:
- Stores player identity (UUID, IP heuristics)
- Tracks whether a player has voted
- Used for duplicate prevention
- Stores vote selections
- Contains no player identity
These datasets must not be joinable.
/modnvote verify participation <pollId>
- Confirms that a player has voted
- Does not reveal vote content
/modnvote verify ballot <pollId> <proof phrase>
- Uses a proof phrase (bearer token)
- Reveals the ballot selection
- Does not identify the voter
The proof phrase must not be derived from or linked to player identity.
DRAFT -> READY -> OPEN -> CLOSED
- DRAFT: fully editable
- READY: validated and locked for editing
- OPEN: accepts votes
- CLOSED: results available
Deletion is allowed only in DRAFT or READY.
Results must be derived from anonymous ballots only.
The system must not:
- use participation records to reconstruct votes
- expose identity-linked vote data
- Append-only event log
- Records poll lifecycle changes and mutations
- Supports integrity verification and debugging
Typical events:
POLL_CREATEDPOLL_UPDATEDPOLL_READYPOLL_OPENEDPOLL_CLOSEDPOLL_DELETED
- No glass pane backgrounds (Bedrock rendering issues)
- Mandatory confirmation step
- All clicks cancelled by default
- Drag and shift-click blocked
- Inventory ownership validated
- No identity ↔ ballot linkage
- GUI layer must remain non-authoritative
- Service layer must be the single source of truth
- Verification must not leak vote content through identity
- Results must be deterministic and reproducible
Planned extensions include:
- Multi-winner STV
- Expanded audit tooling
- Exportable verification data
- Advanced result visualisation
All future features must preserve the privacy and integrity guarantees described above.