Core of the voting system: ballot creation & display, voting-code generation, vote collection, and result display. Part of the E-Voting superproject; pairs with web_sender.
- Laravel 13, PHP
^8.4(dev image: 8.4) - Livewire 4,
league/csv9. No Redis — cache isfile, queue runs onsync/database(predisanddoctrine/dbalremoved). - Component architecture: ballot types live under
app/BallotComponents/<Type>/v1, resolved throughContracts/BallotComponentInterface+Support/ComponentRegistry, returning sealed result DTOs (app/BallotComponents/DTOs).BallotServicedrives result calculation over the registry. (This is the collaborator's architecture; the D1–D11 domain semantics below are our overlay on top of it.) - UUIDs: local
app/Models/Concerns/HasUuidV4.php(random v4). Deliberately not native orderedHasUuids— ordered/sequential UUIDs would leak the order votes were cast, breaking ballot secrecy. Replaced the oldgoldspecdigital/laravel-eloquent-uuid. - CORS is the framework's native
config/cors.php(the oldfruitcake/laravel-corsis gone). - Dev: PHPUnit 13, Paratest 7,
larastan/larastan3 (phpstan 2), Collision 8,spatie/laravel-ignition2;rector/rector2 +barryvdh/laravel-ide-helper3 for mechanical type-declaration / model-property work
php artisan test # Unit + Feature suites
./vendor/bin/paratest # parallel
php -d memory_limit=1024M vendor/bin/phpstan analyse --no-progressPHPStan is at level 8, clean (no baseline). phpstan.neon uses checkModelProperties; framework scaffolding (Exceptions, middleware, providers) is excluded. On the L13 slim skeleton there is no app/Http/Kernel.php — middleware/route wiring lives in bootstrap/app.php. After big edits, vendor/bin/phpstan clear-result-cache.
evote:cache plus ballot/election management: BallotCreate, BallotList, BallotCodesGenerate, BallotComponentCreate, BallotComponentList, ElectionCreate, ElectionList (see app/Console/Commands).
- Vote-integrity fix landed during the upgrade: vote submission now verifies a vote belongs to the ballot it's being cast on (
$vote->ballot->id !== $ballot->id) — previously a vote from another ballot could be accepted. Treat ballot/vote ownership checks as core security; pitch any change before touching them. minimum-stabilityis stilldevincomposer.json— tighten tostablewhen convenient (web_appis alreadystable;web_senderis also stilldev).- The PHP image doesn't install
intl; add it only if a dependency starts requiring it. - As of the 2026-06-13 cutover this is
master(the integrated L13 work). The oldupgrade/laravel-12branch + PR SiVoteEngine#10 are merged/superseded; pre-cutover state is on tagmaster-pre-integration-2026-06-13. See the superprojectCLAUDE.mdfor the full integration story. - 2026-06-22 feature cutover (fast-forward onto
master): ranked-choice results redesign + audit calc (per-rounddecisionrationale, ballot accounting, first-preference matrix onRankedChoiceResult), polishedx-ballot-result-bars, logo-on-surface, and per-ballot results-email columns (result_email_subject/result_email_template) + theresult-previewflow. Pre-flip tagmaster-pre-wizard-merge-2026-06-20; thefeature/ballot-redesign/integration/*branches were deleted (all inmaster).