Goal / Objetivo: real accounts — each user sees only their own data.
This is the biggest structural change: every query, service and endpoint is now scoped to the logged-in user. / Es el cambio estructural más grande: cada consulta, servicio y endpoint queda acotado al usuario logueado.
UserimplementsUserInterface+PasswordAuthenticatedUserInterface(email as identity, hashed password, roles).UserRepositoryalso implementsPasswordUpgraderInterface.composer require symfony/security-bundle;config/packages/security.yamlconfigures an entity provider (users by email), a session-basedjson_login, logout, and access control.
firewalls:
main:
json_login: { check_path: api_login, username_path: email, password_path: password }
logout: { path: api_logout }
access_control:
- { path: ^/api/(login|register|me|health), roles: PUBLIC_ACCESS }
- { path: ^/api, roles: ROLE_USER }POST /api/register— creates a user (password hashed withUserPasswordHasherInterface).POST /api/login— handled by the firewall; the controller returns the user via#[CurrentUser].GET /api/me— the current user, or 401.POST /api/logout— cleared by the firewall.
-
Transactiongains aManyToOne User; imports set it. -
TransactionRepository::findForUser($user); every service (VatService,IrpfService,ForecastService,ChatService,CategorizerService) and the stats SQL now filter by the current user, passed down from each controller via#[CurrentUser] User $user. -
EN: This is the security core of any SaaS: data isolation enforced in the query, so one account can never see another's transactions.
-
ES: Este es el núcleo de seguridad de cualquier SaaS: el aislamiento de datos se impone en la consulta, para que una cuenta nunca vea los movimientos de otra.
AuthContext(useAuth): holds the user, calls/api/meon load, and exposeslogin/register/logout.Appgates everything — logged-out users get theAuthPage(login/register); logged-in users get the app. The navbar shows the email and a Log out button.- Cookies flow automatically because, in dev, the Vite proxy makes frontend and backend the same origin.
- Unit tests updated to the new signatures (pass a
User, stubfindForUser).php bin/phpunit→ OK (11 tests, 37 assertions). - End-to-end (session cookies): register → login →
/api/me→ import (scoped) → a user sees only their own transactions; logged-out requests to/apireturn 401.
Deploy note / Nota de deploy: with the frontend and backend on different domains (e.g. Vercel + Railway), session cookies need
SameSite=None; Secureand CORS with credentials. That's configured at deploy time. / Con frontend y backend en dominios distintos, las cookies de sesión necesitanSameSite=None; Securey CORS con credenciales, que se configuran en el deploy.
Next / Siguiente: production hardening + the live deploy. / endurecimiento de producción y el deploy en vivo.