Sistema completo tipo gubernamental con conteo en tiempo real por WebSocket.
- Cliente: HTML, CSS, JS puro
- Servidor: PHP 8+, Ratchet (WebSocket), Firebase PHP-JWT (JWT)
- BD: MySQL (PDO, patrón Singleton)
- Dependencias: Composer (
cboden/ratchet
,firebase/php-jwt
,guzzlehttp/guzzle
)
gov-voting-php/
├─ app/
│ ├─ Config/
│ ├─ Controllers/
│ ├─ Helpers/
│ ├─ Middleware/
│ ├─ Router/
│ └─ Services/
├─ bin/
│ └─ ws-server.php
├─ public/
│ ├─ api/
│ │ └─ index.php
│ ├─ assets/
│ │ ├─ css/styles.css
│ │ └─ js/{app.js,admin.js,vote.js,results.js}
│ ├─ admin.html
│ ├─ vote.html
│ ├─ results.html
│ └─ index.html
├─ schema.sql
├─ seed/
│ ├─ seed.sql
│ └─ seed.php
├─ composer.json
└─ .env.example
- Clonar/copiar este proyecto.
- Crear archivo
.env
a partir de.env.example
y ajustar credenciales. - Instalar dependencias:
composer install
- Crear BD e importar esquema:
mysql -u root -p < schema.sql
Si prefieres usar tu propio
database.sql
subido previamente, también funciona. El campopartido
encandidates
es opcional y el backend lo ignora. - (Opcional) Ejecutar
seed/seed.php
para crear el usuario admin con bcrypt si tu BD no lo tiene aún:php seed/seed.php
- Iniciar servidor WebSocket:
php bin/ws-server.php
- En otra terminal, iniciar servidor PHP (document root
public/
):php -S localhost:8000 -t public
- Abrir:
- Admin: http://localhost:8000/admin.html
- Votación: http://localhost:8000/vote.html
- Resultados: http://localhost:8000/results.html
- email: [email protected]
- password: admin123
Si importaste
seed/seed.sql
o corristeseed/seed.php
, tendrás este usuario con contraseñabcrypt
.
Si estás usando otro dump donde la contraseña está con SHA-256, el backend también la soporta de forma retrocompatible.
POST /api/auth/login
GET|POST|PUT|DELETE /api/events
GET|POST|PUT|DELETE /api/candidates
GET|POST|PUT|DELETE /api/voters
GET|POST|PUT|DELETE /api/sites
POST /api/votes
(idempotente; registra IP, geolocalización, UA; dispara broadcast)GET /api/results/{event_id}
(totales)
- Servidor en
ws://localhost:8080
- Canal por evento:
event.{event_id}
(suscripción implícita por query?event_id=ID
) - Mensaje:
{ "event_id": 1, "totals": [ { "candidate_id": 1, "votes": 10 }, ... ] }
- Login en Admin, crear evento/candidatos/votantes/sitios o usar
seed.sql
. - Abrir
results.html
(elige evento) y déjalo abierto. - En
vote.html
, ingresa documento, sitio y vota. Verás actualización en vivo.
- JWT para usuarios internos.
- 1 persona = 1 voto por evento (índice único
(event_id, voter_id)
). - Validación de votante activo y asignado al sitio.
- Auditoría completa en
audit_logs
. - IP pública o local + ubicación geográfica (IP geolocation) registradas automáticamente.
- Ajusta
.env
con URL/puertos reales. - Detrás de proxy, asegúrate de pasar
X-Forwarded-For
yX-Real-IP
hacia PHP. - Considera HTTPS (wss://) para WebSocket en producción.