Skip to content

daniel-f-m/notes

Repository files navigation

Player Notes — Historial de Notas de Jugador

Módulo para que agentes de soporte registren y consulten notas internas sobre jugadores.

Stack: Laravel 13 · Livewire 3 · spatie/laravel-permission · PHP 8.4 · MySQL 8.4 en Docker (SQLite para tests y modo nativo)

Puesta en marcha

Solo se necesita Docker — la app corre con Dockerfile + docker-compose.yml (app + MySQL 8.4):

docker compose up --build -d   # espera el healthcheck de MySQL, migra y seedea solo
# → http://localhost:8000

docker compose run --rm --no-deps --entrypoint "" app php artisan test   # suite de tests
docker compose down            # detener (agregar -v para borrar los datos de MySQL)

Con make instalado hay atajos: make up, make test, make logs, make shell, make fresh, make down.

Alternativa con PHP 8.4 local (sin Docker, usa SQLite)
composer install
cp .env.example .env && php artisan key:generate
touch database/database.sqlite
php artisan migrate --seed
php artisan serve

Usuarios de demo (password: password)

Email Rol Puede agregar notas
agent@example.com support-agent ✅ (permiso player-notes.create)
viewer@example.com ❌ solo lectura

Arquitectura

players/{player}/notes  →  PlayerNotesController  →  vista de página
                              ├─ <livewire:player-notes-list>    (Fecha · Autor · Nota)
                              └─ <livewire:create-player-note>   (solo con @can)
                                     │  save(): authorize → validate → repositorio
                                     └─ dispatch('player-note-created') ─► #[On] en la lista → re-render

Componentes Livewire ──► PlayerNoteRepositoryInterface (abstracción)
                              └─ EloquentPlayerNoteRepository (binding en RepositoryServiceProvider)

Decisiones de diseño

  • Patrón Repositorio con inversión de dependencias (SOLID/DIP): los componentes dependen de PlayerNoteRepositoryInterface; la implementación Eloquent se resuelve vía binding en RepositoryServiceProvider. Cambiar de almacenamiento (u otro ORM) no toca la capa de presentación.
  • Dos componentes Livewire comunicados por evento (SRP): el formulario despacha player-note-created y la lista lo escucha con #[On] — la tabla se refresca sin recargar la página (equivalente moderno de emit/$listeners de Livewire 2).
  • Permisos en dos niveles: @can('player-notes.create') controla la visibilidad del formulario, y $this->authorize(...) dentro de save() lo exige server-side (una UI oculta no es seguridad). No se agregó una Policy: spatie ya registra cada permiso en el Gate y no hay lógica por instancia que justifique esa indirección.
  • PlayerNote::MAX_LENGTH (const tipada PHP 8.3+) como única fuente del límite de caracteres para la regla de validación, el maxlength del textarea y el tamaño de la columna.
  • Integridad referencial: borrar un jugador elimina sus notas (cascadeOnDelete); no se puede borrar un usuario con notas escritas (restrictOnDelete) para preservar el historial de auditoría.
  • Validación: rules() + messages() en el componente — nota obligatoria, máx. 500 caracteres, mensajes en español.

Infraestructura (Docker)

  • Dockerfile multi-stage: las dependencias se instalan en un stage composer:2 y la app corre sobre php:8.4-cli (+ pdo_mysql) como usuario no-root, con imágenes públicas oficiales. El código va horneado en la imagen — docker compose up no depende de permisos del host.
  • docker-compose.yml: servicio app (puerto 8000) + mysql:8.4 con healthcheck; la app arranca recién cuando MySQL responde consultas (depends_on: condition: service_healthy).
  • Entrypoint autosuficiente: en cada boot materializa las variables del contenedor en .env (necesario porque artisan serve solo propaga una lista fija de variables a sus workers), ejecuta migrate con reintentos y corre los seeders — que son idempotentes, así el boot es repetible sin duplicar datos.
  • Tests aislados por diseño: tests/bootstrap.php fuerza SQLite en memoria en todos los canales de entorno ($_SERVER/$_ENV/putenv), de modo que correr la suite dentro del contenedor jamás toca la base MySQL de demo.

Mapa del módulo

Capa Archivos
Migraciones database/migrations/*_create_players_table.php, *_create_player_notes_table.php
Modelos app/Models/Player.php, app/Models/PlayerNote.php, app/Models/User.php
Repositorio app/Repositories/Contracts/PlayerNoteRepositoryInterface.php, app/Repositories/EloquentPlayerNoteRepository.php, app/Providers/RepositoryServiceProvider.php
Livewire app/Livewire/CreatePlayerNote.php, app/Livewire/PlayerNotesList.php + vistas en resources/views/livewire/
HTTP app/Http/Controllers/PlayerNotesController.php, PlayerController.php, Auth/LoginController.php, routes/web.php
Permisos/Demo database/seeders/RolesAndPermissionsSeeder.php, DatabaseSeeder.php
Tests tests/Feature/PlayerNotesTest.php, tests/bootstrap.php
Infraestructura Dockerfile, docker-compose.yml, docker/entrypoint.sh, Makefile

Tests

make test (o el docker compose run equivalente) — 10 tests / 29 aserciones sobre SQLite en memoria. El módulo cubre:

  • Usuario autorizado crea una nota → persiste en BD, resetea el campo y despacha el evento.
  • Validación: nota vacía (required) y nota que excede el máximo (max:500).
  • Usuario sin permiso: la acción save() responde 403 y el formulario no se renderiza.
  • La página lista fecha, autor (nombre del User) y contenido de cada nota.
  • La lista se refresca al recibir el evento player-note-created.
  • Invitados son redirigidos al login.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors