Skip to content

Statistiques et analytiques

English version
Retour au sommaire


Types d'événements trackés

L'application enregistre automatiquement 3 types d'événements utilisateur :

Type (event_type) Déclenché quand Ce que ça mesure
unlock_language Un joueur déverrouille une langue Popularité / ventes par langue
view_card Un joueur consulte une carte Engagement par carte
play_audio Un joueur écoute un audio Utilisation des enregistrements

Structure de la table statistics

CREATE TABLE statistics (
  id          UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  language_id UUID REFERENCES languages(id) ON DELETE CASCADE,
  card_id     UUID REFERENCES cards(id) ON DELETE CASCADE,
  item_id     UUID REFERENCES items(id) ON DELETE CASCADE,
  event_type  VARCHAR(50) NOT NULL,  -- 'unlock_language', 'view_card', 'play_audio'
  count       INTEGER DEFAULT 1,
  event_date  DATE NOT NULL,
  created_at  TIMESTAMPTZ DEFAULT NOW()
);

Clé d'unicité : (language_id, card_id, item_id, event_type, event_date) — les événements sont agrégés par jour (upsert avec incrémentation de count).


Structure de la table quiz_sessions

CREATE TABLE quiz_sessions (
  id               UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  language_id      UUID REFERENCES languages(id) ON DELETE CASCADE,
  category_slug    VARCHAR(255) NOT NULL,
  category_name    VARCHAR(255),
  total_questions  INTEGER NOT NULL,
  score            INTEGER,
  started_at       TIMESTAMPTZ DEFAULT NOW(),
  completed_at     TIMESTAMPTZ,
  created_at       TIMESTAMPTZ DEFAULT NOW()
);
  • Une session quiz_sessions est créée quand un joueur démarre un quiz
  • score et completed_at sont renseignés quand le joueur termine le quiz
  • Si completed_at est NULL, le quiz a été abandonné

Visualiser les statistiques dans le dashboard

La plupart des analyses sont accessibles directement dans le tableau de bord. Pour des analyses avancées, vous pouvez accéder directement à la base de données PostgreSQL.


Requêtes SQL utiles

Nombre total de déverrouillages

SELECT COUNT(*) AS total_unlocks
FROM statistics
WHERE event_type = 'unlock_language';

Déverrouillages par langue (période donnée)

SELECT l.name, SUM(s.count) AS unlocks
FROM statistics s
JOIN languages l ON s.language_id = l.id
WHERE s.event_type = 'unlock_language'
  AND s.event_date >= '2026-01-01'
  AND s.event_date <= '2026-05-31'
GROUP BY l.name
ORDER BY unlocks DESC;

Top 10 cartes les plus consultées (toutes langues)

SELECT c.card_number, c.type, l.name, SUM(s.count) AS views
FROM statistics s
JOIN cards c ON s.card_id = c.id
JOIN languages l ON c.language_id = l.id
WHERE s.event_type = 'view_card'
GROUP BY c.card_number, c.type, l.name
ORDER BY views DESC
LIMIT 10;

Audios les plus écoutés pour une langue

SELECT i.original_text, i.translation, SUM(s.count) AS plays
FROM statistics s
JOIN items i ON s.item_id = i.id
JOIN cards c ON i.card_id = c.id
WHERE s.event_type = 'play_audio'
  AND c.language_id = 'UUID_DE_LA_LANGUE'
GROUP BY i.original_text, i.translation
ORDER BY plays DESC
LIMIT 10;

Activité quotidienne sur 30 jours

SELECT event_date, event_type, SUM(count) AS total
FROM statistics
WHERE event_date >= CURRENT_DATE - INTERVAL '30 days'
GROUP BY event_date, event_type
ORDER BY event_date DESC;

Performances quiz — taux de complétion

SELECT
  l.name AS language,
  qs.category_name,
  COUNT(*) AS sessions_started,
  COUNT(qs.completed_at) AS sessions_completed,
  ROUND(COUNT(qs.completed_at)::numeric / COUNT(*)::numeric * 100, 1) AS completion_rate,
  ROUND(AVG(qs.score::numeric / qs.total_questions::numeric * 100), 1) AS avg_score_pct
FROM quiz_sessions qs
JOIN languages l ON qs.language_id = l.id
GROUP BY l.name, qs.category_name
ORDER BY l.name, qs.category_name;

Statistiques hors ligne

Les joueurs hors ligne accumulent des événements dans une queue locale (IndexedDB). Ces événements sont synchronisés automatiquement à la reconnexion.

Impact : - Les statistiques temps réel peuvent être légèrement en retard pour les utilisateurs hors ligne - Les données sont toujours cohérentes à terme (pas de perte de données) - Il n'y a pas de moyen de forcer la synchronisation côté admin


Exporter les statistiques

Via pg_dump (export complet)

# Sur le serveur ou via tunnel SSH
pg_dump -h localhost -U postgres -d racines \
  --table=statistics --table=quiz_sessions \
  -F c -f stats_backup.dump

Via psql (export CSV)

psql -h localhost -U postgres -d racines -c \
  "\COPY (SELECT * FROM statistics WHERE event_date >= '2026-01-01') \
  TO '/tmp/stats_2026.csv' WITH CSV HEADER;"

Via l'API admin

L'endpoint GET /api/admin/statistics retourne les statistiques agrégées en JSON :

GET /api/admin/statistics?period=30d&language_id=[UUID]

Il n'existe pas d'export CSV natif dans l'interface graphique. Pour des exports réguliers, mettez en place un script cron côté serveur.


Étapes suivantes