fix: corrections post-audit (traçabilité, identité État, accents, graphique mobile)

Backend:
- table audits réellement alimentée via trait Auditable (observers Eloquent)
  sur Utilisateur, SaisieTracker, Feed, Emotion ; mot de passe jamais loggé
- 4 nouveaux tests (19/19 au total)

Frontend web:
- en-tête/pied République Française ajoutés aux pages connexion/inscription
- bouton variant danger réellement rouge (tokens erreur DSFR)

Mobile:
- ~30 libellés ré-accentués (Intensité, Succès, Déconnexion, Répartition...)
- Colors.secondary = rouge Marianne #E1000F (différenciation cartes/icônes)
- vrai camembert SVG des rapports (react-native-svg)

Docs: plans oraux mis à jour (audits actif, 29 tests, stockage JWT en Q/R)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Azmog
2026-06-19 11:17:40 +02:00
parent 7be7bec53d
commit 4f54340e89
25 changed files with 580 additions and 49 deletions
+86
View File
@@ -0,0 +1,86 @@
<?php
namespace App\Models\Concerns;
use App\Models\Audit;
use Illuminate\Database\Eloquent\Model;
/**
* Trait de traçabilité Eloquent.
*
* Ajoute automatiquement une ligne dans la table `audits` lors des
* événements created / updated / deleted du modèle qui l'utilise.
*/
trait Auditable
{
/**
* Champs sensibles à ne jamais stocker dans l'audit.
*
* @var array<int, string>
*/
protected static array $champsAuditExclus = [
'password',
'remember_token',
];
/**
* Enregistre les hooks d'audit sur les événements du modèle.
*/
public static function bootAuditable(): void
{
static::created(function (Model $model) {
$model->ecrireAudit('creation', null, $model->valeursAuditables($model->getAttributes()));
});
static::updated(function (Model $model) {
$modifies = array_keys($model->getDirty());
if ($modifies === []) {
return;
}
$anciennes = $model->valeursAuditables($model->getOriginal());
$nouvelles = $model->valeursAuditables($model->getDirty());
$model->ecrireAudit(
'modification',
array_intersect_key($anciennes, $nouvelles),
$nouvelles
);
});
static::deleted(function (Model $model) {
$model->ecrireAudit('suppression', $model->valeursAuditables($model->getAttributes()), null);
});
}
/**
* Filtre les champs sensibles d'un jeu d'attributs.
*
* @param array<string, mixed> $valeurs
* @return array<string, mixed>
*/
protected function valeursAuditables(array $valeurs): array
{
return array_diff_key($valeurs, array_flip(static::$champsAuditExclus));
}
/**
* Insère une ligne d'audit.
*
* @param array<string, mixed>|null $anciennes
* @param array<string, mixed>|null $nouvelles
*/
protected function ecrireAudit(string $action, ?array $anciennes, ?array $nouvelles): void
{
Audit::create([
'utilisateur_id' => auth()->id(),
'action' => $action,
'table_cible' => $this->getTable(),
'enregistrement_id' => $this->getKey(),
'anciennes_valeurs' => $anciennes,
'nouvelles_valeurs' => $nouvelles,
'ip_address' => request()->ip(),
]);
}
}
+2 -1
View File
@@ -2,6 +2,7 @@
namespace App\Models;
use App\Models\Concerns\Auditable;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
@@ -10,7 +11,7 @@ use Illuminate\Database\Eloquent\Relations\HasMany;
class Emotion extends Model
{
use HasFactory;
use Auditable, HasFactory;
protected $table = 'emotions';
+2 -1
View File
@@ -2,6 +2,7 @@
namespace App\Models;
use App\Models\Concerns\Auditable;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
@@ -9,7 +10,7 @@ use Illuminate\Database\Eloquent\Relations\BelongsTo;
class Feed extends Model
{
use HasFactory;
use Auditable, HasFactory;
protected $table = 'feeds';
+2 -1
View File
@@ -2,13 +2,14 @@
namespace App\Models;
use App\Models\Concerns\Auditable;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
class SaisieTracker extends Model
{
use HasFactory;
use Auditable, HasFactory;
protected $table = 'saisie_trackers';
+2 -1
View File
@@ -2,6 +2,7 @@
namespace App\Models;
use App\Models\Concerns\Auditable;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
@@ -13,7 +14,7 @@ use Tymon\JWTAuth\Contracts\JWTSubject;
class Utilisateur extends Authenticatable implements JWTSubject
{
use HasFactory, Notifiable, SoftDeletes;
use Auditable, HasFactory, Notifiable, SoftDeletes;
protected $table = 'utilisateurs';