feat(admin): THI-234 Phase 9 analytics widgets (Santé Supabase + activity heatmap)#370
Merged
Conversation
…ivity heatmap Replace 2 of the 4 AdminPanel placeholder widgets with live data: - Santé Supabase: total users, active 7d, lessons completed 30d/total, top 5 lessons - Activité élèves: GitHub-style 52-week heatmap (THI-77) Data via 2 SECURITY DEFINER RPCs (migration 032) with an internal super_admin gate (raise PERMISSION_DENIED otherwise) + REVOKE public/anon — cross-user aggregates without exposing rows to non-admins. Isolation proven empirically via REST+JWT: super_admin 200, student 400 PERMISSION_DENIED, anon 401. Sentry + Application health stay placeholders (Phase 9 v2 — need API route + secret). Counts only, no PII. - migration 032 (applied to prod, additive) - Database.Functions types for the 2 RPCs (zero any) - useAdminAnalytics hook (parallel RPC fetch, read-only) - pure heatmap helpers (buildHeatmapGrid/heatmapLevel/heatmapMax) + tests - AdminPanel widgets data-driven (loading/error/empty states) - 24 new tests; adminPanel.test rewritten for the new widgets Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
There was a problem hiding this comment.
Sorry @thierryvm, you have reached your weekly rate limit of 500000 diff characters.
Please try again later or upgrade to continue using Sourcery
…or W2) When the platform has zero completions the aria-label said "… jour le plus actif 0" which is confusing for screen readers. Use a clear "Aucune activité sur les 52 dernières semaines." in that case. THI-234. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…le-auditor) The status-triage <select> (THI-320) used text-sm (14px) → Safari iOS auto-zooms the page on focus when a form control is < 16px. Bump to text-base (16px). Out-of-scope drive-by surfaced by the THI-234 mobile gate (the select renders on the admin page this PR touches). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ode-reviewer) - active_users_7d now filters `completed = true` like the sibling metrics. Redundant today (ProgressContext only upserts completed rows — verified) but defensive + consistent if the upsert ever stamps completed_at on lesson-start. Re-applied to prod via CREATE OR REPLACE (idempotent). - useAdminAnalytics surfaces BOTH RPC errors (Promise.all) instead of masking the second — easier debugging when both fail from the same root cause. code-reviewer findings #1 + #4 (THI-234). #2/#5 (runtime narrowing, useId) → backlog. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
THI-234 — Phase 9 Admin Panel : widgets analytics live
Remplace 2 des 4 widgets placeholder de
/app/adminpar des données réelles (démo écoles, budget 0€, sans table dédiée).Changements
SECURITY DEFINER(admin_platform_statsjson,admin_activity_heatmaptable) agrégeant cross-userprofiles+progress, gatesuper_admininterne (raisePERMISSION_DENIED) + REVOKE public/anon +set search_path. Appliquée en prod (additive, calquée sur le patternapprove_teacher027).useAdminAnalytics(fetch parallèle, read-only) + helpers heatmap purs + typesDatabase.Functions(zéroany).Sécurité — isolation prouvée empiriquement (REST+JWT)
PERMISSION_DENIED(gate role)permission denied for function(REVOKE public/anon)Defense in depth : UI gated
<RequireRole allowed={['super_admin']}>. Counts only, aucune PII.Tests
24 nouveaux (helper 11 + hook 4 + AdminPanel 9). type-check + lint clean.
⚠️ Note d'intégrité : 1 test d'intégration
approveTeacher(cross-institution) est flaky stateful (état test users partagé en prod — dette THI-334), sans rapport avec THI-234, skippé en CI, et passe en isolation (11/11).Validation
Gates en cours :
security-auditor+ui-auditor+mobile-responsive-auditor(parallèle) →feature-dev:code-reviewer. Voie A preview desktop + mobile 390px à confirmer avant merge.🤖 Generated with Claude Code