feat: multi-user reading progress & backoffice impersonation

- Scope all reading progress (books, series, stats) by user via
  Option<Extension<AuthUser>> — admin sees aggregate, read token sees own data
- Fix duplicate book rows when admin views lists (IS NOT NULL guard on JOIN)
- Add X-As-User header support: admin can impersonate any user from backoffice
- UserSwitcher dropdown in nav header (persisted via as_user_id cookie)
- Per-user filter pills on "Currently reading" and "Recently read" dashboard sections
- Inline username editing (UsernameEdit component with optimistic update)
- PATCH /admin/users/:id endpoint to rename a user
- Unassigned read tokens row in users table
- Komga sync now requires a user_id — reading progress attributed to selected user
- Migration 0051: add user_id column to komga_sync_reports
- Nav breakpoints: icons-only from md, labels from xl, hamburger until md

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-24 12:47:58 +01:00
parent 232ecdda41
commit bc796f4ee5
22 changed files with 1326 additions and 152 deletions

View File

@@ -6,6 +6,7 @@ const fr = {
"nav.libraries": "Bibliothèques",
"nav.jobs": "Tâches",
"nav.tokens": "Jetons",
"nav.users": "Utilisateurs",
"nav.settings": "Paramètres",
"nav.navigation": "Navigation",
"nav.closeMenu": "Fermer le menu",
@@ -94,6 +95,7 @@ const fr = {
"dashboard.pageProgress": "p. {{current}} / {{total}}",
"dashboard.noCurrentlyReading": "Aucun livre en cours",
"dashboard.noRecentlyRead": "Aucun livre lu récemment",
"dashboard.allUsers": "Tous",
// Books page
"books.title": "Livres",
@@ -403,6 +405,21 @@ const fr = {
"tokens.revoked": "Révoqué",
"tokens.active": "Actif",
"tokens.revoke": "Révoquer",
"tokens.user": "Utilisateur",
"tokens.noUser": "Aucun (admin)",
"tokens.apiTokens": "Tokens API",
// Users page
"users.title": "Utilisateurs",
"users.createNew": "Créer un utilisateur",
"users.createDescription": "Créer un compte utilisateur pour accès lecture",
"users.username": "Nom d'utilisateur",
"users.createButton": "Créer",
"users.name": "Nom d'utilisateur",
"users.tokenCount": "Nb de jetons",
"users.createdAt": "Créé le",
"users.actions": "Actions",
"users.noUsers": "Aucun utilisateur",
// Settings page
"settings.title": "Paramètres",