Ajoute la V1 fonctionnelle : upload invité, galerie admin, QR code, backend Supabase

Schéma dédié `photobooth` (jamais exposé via PostgREST, accès exclusivement
via fonctions SECURITY DEFINER dans public) avec RLS, policies Storage sur
bucket privé event-photos, Edge Functions admin-gallery et expire-events,
et job pg_cron d'expiration J+7. Le tout déployé et testé en conditions
réelles sur le projet Supabase kevin-lecou-hub avant relecture sécurité
(faille d'abus sur insert_public_photo corrigée en cours de route).

Côté front : page upload invité (compression + HEIC + RGPD), galerie admin
avec export ZIP, générateur de QR code autonome. Workflow n8n de purge
Storage J+7 fourni (à activer manuellement côté n8n).
This commit is contained in:
2026-09-16 11:32:31 +02:00
parent 2007eab006
commit 9b1461978b
37 changed files with 6255 additions and 4 deletions
+58
View File
@@ -0,0 +1,58 @@
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<title>Galerie événement — admin</title>
<!--
Cette page est servie pour toute URL du type /admin/<slug> (le slug est lu
côté client depuis window.location.pathname, le token depuis les query
params ?token=..., voir gallery.js). Comme pour /e/<slug> (voir
src/e/index.html), ça suppose une règle de réécriture côté serveur qui
renvoie ce fichier pour toute requête sous /admin/* — hors scope de ce
fichier front, à mettre en place lors du déploiement.
-->
<meta name="robots" content="noindex, nofollow">
<link rel="stylesheet" href="style.css">
</head>
<body>
<main class="page">
<header class="page__header">
<h1 id="event-name">Galerie événement</h1>
<p id="event-meta" class="event-meta" hidden></p>
</header>
<section id="status-loading" class="state-block" role="status">
<p>Chargement de la galerie…</p>
</section>
<section id="status-error" class="state-block state-block--error" hidden role="alert">
<p id="status-error-message"></p>
<button type="button" id="retry-btn" hidden>Réessayer</button>
</section>
<section id="gallery-content" hidden>
<p id="status-banner" class="status-banner" hidden></p>
<div class="toolbar">
<button type="button" id="refresh-btn" class="btn btn--secondary">Actualiser</button>
<button type="button" id="download-zip-btn" class="btn">Télécharger tout (ZIP)</button>
</div>
<p id="zip-status" class="zip-status" aria-live="polite" hidden></p>
<p id="empty-state" class="state-block" hidden></p>
<ul id="photo-grid" class="photo-grid"></ul>
</section>
</main>
<!--
config.js n'est PAS commité (voir .gitignore) : copier config.example.js
en config.js et renseigner les vraies valeurs avant déploiement. Chargé en
script classique (donc synchrone, avant le module) pour garantir que
window.__PHOTOBOOTH_CONFIG__ existe avant l'exécution de gallery.js.
-->
<script src="config.js"></script>
<script type="module" src="gallery.js"></script>
</body>
</html>