15 Commits

Author SHA1 Message Date
yann64 aaf0fc2cd9 Import/export CSV des lieux
Export (GET lieux/export/csv) :
- Colonnes : nom, code, type, lieu_parent (nom_long), latitude, longitude, note
- BOM UTF-8, séparateur point-virgule

Import (GET/POST lieux/import) :
- Correspondance par nom de colonne (colonne nom obligatoire)
- Résolution du parent par nom_long exact
- Résolution du type par nom exact
- Détection automatique du séparateur ; ou ,
- nom_long recalculé automatiquement par le modèle

Boutons ↓ CSV, ↑ Importer CSV et + Nouveau lieu dans la liste des lieux.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-05 20:06:46 +02:00
yann64 cdbf6d458c Import CSV des relevés d'une source
- ImportController : create() (formulaire) + store() (traitement)
- Détection automatique du séparateur ; ou ,
- Suppression du BOM UTF-8
- Correspondance colonnes ↔ champs par libellé
- Parsing des types : date (avec calendrier), booléen, nombre, lieu (recherche par nom_long), texte
- Vue sources/import.blade.php : formulaire + liste des colonnes attendues
- Routes sources.import.create / sources.import.store
- Bouton "↑ Importer CSV" dans la fiche source (soumis aux droits create releve)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-05 20:05:03 +02:00
yann64 ff615ca0a1 Suppression de l'export GEDCOM
- Routes export.source et export.recherche supprimées
- ExportController : méthodes source() et recherche() supprimées,
  imports GedcomExportService/DbCompat/Releve/SourceStatus/DB retirés
- Boutons GEDCOM retirés de sources/show, releves/index et recherche/index

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-05 20:01:33 +02:00
yann64 fdd81977c2 Export CSV des relevés d'une source
- ExportController::sourceCsv() : génère un CSV avec BOM UTF-8 (compatible Excel)
  séparateur point-virgule, en-têtes = labels des champs, valeurs formatées
  (dates avec calendrier si non grégorien, lieux = nom_long, booléens Oui/Non)
- Route GET export/source/{source}/csv → export.source.csv
- Boutons ↓ CSV et ↓ GEDCOM dans la section relevés de la fiche source

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-05 19:39:21 +02:00
yann64 a1860e9462 Page carte interactive des relevés (Leaflet + OpenStreetMap)
- CarteController : index() + data() (JSON) — requête lieux géolocalisés
  ayant des sources avec relevés, agrégats par lieu
- Lieu model : relations sources() et releves() (hasManyThrough)
- Vue carte/index.blade.php : carte Leaflet pleine hauteur, marqueurs
  colorés par nombre de sources (taille/couleur proportionnels),
  popup par lieu avec liste des sources, statuts, années et lien recherche
- Tuiles OpenStreetMap inversées en mode sombre
- Route GET /carte + GET /carte/data
- Lien "Carte" dans la navigation desktop et mobile
- @stack('head') dans le layout pour injecter Leaflet uniquement sur la page carte

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-04 21:02:28 +02:00
yann64 f530f55577 Mode sombre, option désactivation mises à jour, user-picker avec recherche
- Dark mode complet : darkMode:'class' Tailwind, sélecteur clair/sombre/auto
  dans la navigation (mémorisé dans localStorage, sans flash au chargement) ;
  53 vues et 8 composants Breeze mis à jour avec classes dark:
- Composant user-picker : fenêtre modale avec recherche temps réel (nom/email)
  remplace les <select> d'ajout de membres dans sections et sources
- Paramètres : option "Désactiver la vérification automatique des mises à jour"
  (case à cochage auto-soumise, route POST parametres/updates)
- Panneau "Paramètres généraux" remonté en tête de la page de paramètres
- README recentré sur l'installation manuelle hébergement PHP+MySQL
- VERSION 1.0.1

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-04 19:46:22 +02:00
yann64 07ab2a7063 Configuration SMTP et 2FA par code PIN e-mail
Paramètres du site :
- Nouvelle section "Serveur SMTP" avec host, port, chiffrement,
  identifiant, mot de passe, adresse/nom d'expéditeur
- Bouton "Envoyer un e-mail de test" (AJAX via Symfony EsmtpTransport) :
  tente la connexion + envoie un message réel à l'admin
- Badge "Configuré — 2FA actif" quand SMTP est en place
- Suppression de la configuration possible

Authentification 2FA :
- Si SMTP configuré : après validation identifiant/mot de passe,
  l'utilisateur est déconnecté, un PIN à 6 chiffres est généré,
  haché (bcrypt) et stocké en session, envoyé par e-mail (10 min)
- Page /2fa : saisie du PIN, bouton "Renvoyer le code", retour login
- Si l'envoi e-mail échoue : fallback sans 2FA (logue l'erreur)
- Si SMTP non configuré : login standard inchangé

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-04 18:59:18 +02:00
yann64 b608501f39 Import/export CSV utilisateurs, filtre statut et titre du site modifiable
Utilisateurs :
- Filtre actif/inactif dans la liste (status=active|inactive)
- Export CSV avec les filtres actifs — séparateur ;, BOM UTF-8 (compatible Excel)
- Import CSV : détection auto du séparateur, validation ligne par ligne,
  mot de passe temporaire généré + affiché une seule fois dans les résultats
- Téléchargement d'un fichier modèle CSV

Paramètres du site :
- Champ "Titre du site" (site_name dans site_settings.json)
- Titre partagé via SiteSettingsService::siteName() et injecté dans config('app.name')
  au boot — s'applique partout sans modifier .env

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-04 18:48:36 +02:00
yann64 caf7ad7fe2 Ajout de l'assistant d'installation web et corrections de navigation
- Wizard d'installation en 5 étapes (/setup) : prérequis PHP, base de données
  (PostgreSQL/MySQL avec test de connexion AJAX), paramètres app, compte admin,
  résultat — génère le .env, migre et crée l'administrateur
- CheckInstallation middleware : redirige vers /setup si non installé,
  protège /setup si déjà installé ; storage/installed comme marqueur
- Menu Administration : remplacé par le composant x-dropdown Breeze (même
  positionnement que le menu utilisateur — corrige le débordement en haut)
- Logo navbar : adaptatif via h-full/py-1.5 (s'adapte à la hauteur de la barre)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-04 18:39:55 +02:00
yann64 f57ae068b9 Logo du site, favicon et contrôle des inscriptions
SiteSettingsService : persistance JSON dans storage/app/site_settings.json
  (pas de migration DB — survit aux mises à jour sans table supplémentaire)

Logo :
- Upload admin (PNG/JPG/SVG/WebP, max 2 Mo) → storage/app/public/site/logo.{ext}
- Favicon <link rel="icon"> injecté dans app.blade.php et guest.blade.php
- Logo affiché dans la barre de navigation (h-8, object-contain)
- Logo affiché sur la page de connexion (guest layout)
- Page d'accueil welcome.blade.php entièrement refaite : logo + bouton connexion
  (remplacement du template Laravel par défaut)
- Suppression du logo possible depuis Admin > Paramètres du site

Inscriptions :
- Désactivées par défaut (registration_enabled=false dans site_settings.json)
- RegisteredUserController : redirige vers /login si inscription désactivée
  (GET /register → redirect + message ; POST /register → abort 403)
- Page d'accueil : bouton "Créer un compte" masqué si inscriptions désactivées
- Admin > Paramètres du site : toggle checkbox pour activer/désactiver

AppServiceProvider : partage $siteLogoUrl et $registrationEnabled avec toutes les vues

Navigation : lien "Paramètres du site" en bas du menu Administration

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-04 18:01:38 +02:00
yann64 dbf0465b0a Comptes actifs/inactifs + stats de section dans le tableau de bord
Utilisateurs actifs/inactifs :
- Migration : colonne is_active (boolean, default true) sur users
- Middleware EnsureUserIsActive : déconnecte les utilisateurs désactivés sur chaque requête
- LoginRequest : bloque la connexion si is_active=false (message explicite)
- Admin : bouton Activer/Désactiver dans la liste et la page d'édition
  Protections : impossible de désactiver son propre compte ou le dernier admin actif
- Badge « Inactif » + opacité réduite sur la ligne dans la liste admin
- Sélection de membres (sources) : filtre is_active=true

Sources liées aux sections :
- Migration : colonne section_id nullable FK sur sources
- Source::section() BelongsTo + Section::sources() HasMany
- Formulaire sources/_form : sélecteur de section (sections de l'utilisateur ou toutes pour admin)
- SourceController : passe les sections disponibles aux vues create/edit

Tableau de bord enrichi (DashboardController) :
- Membres et responsables : stats par section (sources par statut, total relevés)
  compteurs cliquables → liste filtrée, sources récentes de la section
- Mes sources assignées (tri par urgence) + mes derniers relevés (inchangés)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-04 17:50:56 +02:00
yann64 ba7fe10329 Versioning, déploiement et mise à jour automatique
Gestion des versions :
- Fichier VERSION (1.0.0) comme source de vérité
- config/update.php : URL Gitea, AUTO_UPDATE (false par défaut), rétention des sauvegardes

Artisan commands :
- app:check-update  : interroge l'API Gitea, cache Redis 1h, déclenche app:update si AUTO_UPDATE=true
- app:update        : télécharge l'archive, sauvegarde pg_dump, rsync, composer install, migrate, reload php-fpm
- app:rollback      : liste les sauvegardes et restaure via psql

UpdateService :
- Téléchargement via Http::sink() (streaming, pas de charge mémoire)
- Sauvegarde pg_dump dans storage/app/backups/ avant chaque mise à jour
- Rechargement php-fpm gracieux (kill -USR2 1) sans downtime
- Purge automatique des anciennes sauvegardes (configurable)

Docker (refactor pour volume-mount) :
- Dockerfile : runtime seulement (PHP + extensions + composer + rsync + pg_client)
  Le code n'est plus copié dans l'image → les mises à jour ne nécessitent pas de rebuild
- entrypoint.sh : composer install + key:generate + caches au démarrage du container
- docker-compose.prod.yml : montage du code comme volume (.:/var/www/html)

Scripts de déploiement :
- bin/build-release.sh : rsync + tar.gz + sha256, exclut vendor/node_modules/tests
- install.sh : guide d'installation Docker complète (première mise en service)

Interface admin :
- Bandeau "mise à jour disponible" dans le dashboard admin (version courante + cible)
- Badge version + icône "à jour" en pied de tableau de bord
- Commande à copier-coller pour appliquer depuis le container

Planification :
- routes/console.php : Schedule::command('app:check-update')->daily()
- .env.example : variables GITEA_*, AUTO_UPDATE, UPDATE_BACKUPS_TO_KEEP

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-04 17:38:39 +02:00
yann64 c790691200 Étape 10 : interface admin (tableau de bord + gestion utilisateurs)
- DashboardController : stats globales (sources par statut, relevés, utilisateurs, activité mensuelle 6 mois)
- UserController : liste filtrée (nom/email/rôle) + édition de rôle avec protections (auto-demotion, dernier admin)
- Vue admin/dashboard : compteurs par statut cliquables, graphique barres mensuel, sources à valider, relevés récents
- Vue admin/utilisateurs : liste paginée avec sections et sources assignées, page d'édition avec radio-cards
- Dashboard principal enrichi : bloc accès admin, mes sources assignées triées par urgence, mes derniers relevés
- Navigation : ajout Tableau de bord admin et Utilisateurs dans le menu Administration

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-04 17:21:50 +02:00
yann64 d064f8d28e Étapes 6-9 + types de lieux + picker + filtres
- Étape 6 : formulaire de saisie dynamique des relevés (piloté par source_type_fields, calendriers grégorien/julien/républicain)
- Étape 7 : workflow de statut des sources + notifications mail+DB (SourceAValider, SourceRejetee)
- Étape 8 : recherche fulltext PostgreSQL avec filtres type/lieu/années et CTE récursive pour les subdivisions de lieux
- Étape 9 : export GEDCOM 5.5.1 (GedcomExportService + DateConversionService)
- Types de lieux : CRUD admin (LieuTypeController) avec champ ordre
- Composant lieu-picker : modale Alpine.js avec recherche AJAX + debounce
- Filtres sources : statut, type, lieu (CTE récursive), période annee_debut/annee_fin
- Filtres lieux : type, texte, lieu parent avec descendants (CTE récursive)
- Migration : lieu_id + annee_debut + annee_fin sur sources

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-04 17:17:53 +02:00
yann64 7609d35287 Initial scaffold : Laravel 12 + PostgreSQL + auth + domaine métier (étapes 1-5)
- Laravel 12 sur PHP 8.5, Breeze (Blade/Tailwind/Alpine.js)
- Docker Compose dev (PostgreSQL 18 + Redis) et prod (stack complète + nginx)
- Migrations et models : lieux, sections, dépôts, source_types/fields, sources, relevés
  - Colonne JSONB data sur releves avec colonnes générées indexées (nom, prenom, date_evenement)
  - Index GIN pour la recherche fulltext
- Enums : UserRole, SourceStatus (avec transitions), CalendarType, FieldType
- RoleMiddleware (alias `role`) + helpers isAdmin/isSectionManager sur User
- CRUD Lieux (arbre hiérarchique, calcul nom_long en cascade)
- CRUD admin : Sections (+ gestion membres), Dépôts, Types de sources (+ champs dynamiques, drag & drop)
- CRUD Sources : visibilité filtrée par rôle, assignation membres, workflow de statut

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-04 16:16:37 +02:00