Javis OS
Javis OS is an Agentic AI that assists entrepreneurs in business tasks, helping them grow their work.
AI translation
Plateforme de gestion des églises, ministères et communautés chrétiennes.
Translation pending
BusinessTypeScript · PLpgSQLGitHub @RodrigueSehinOnlineOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
No updates detected yet. GitHub releases will appear here.
Owners of public repositories under a personal GitHub account can sign in to verify ownership and manage the introduction themselves. No administrator approval is needed.
Sign in, generate a verification file, and commit it to this repository’s default branch within 30 minutes. Files on other branches or forks do not count. Then check the file below to manage the project without administrator approval. Keep the file to retain your access.
If needed, you will go to sign-in. After signing in, return here and press your chosen verification button again.
Run /nomorevibe verify in your project folder to verify ownership and manage the introduction yourself.
Verify in one minuteAsk about other verification options
Loading the full README. The saved excerpt is shown below.
SaaS de gestion des églises, ministères et communautés chrétiennes. Voir docs/architecture/ pour l'architecture technique complète (STEP 01) et le plan de développement par phase. Sur cette machine, Node.js n'était pas installé au démarrage du projet : une version portable a été téléchargée dans %LOCALAPPDATA%\nodejs-portable\node-v24.21.0-win-x64 et ajoutée au PATH utilisateur. Ouvrez un nouveau terminal pour que node/npm soient reconnus directement ; sinon utilisez le chemin complet vers node.exe/npm.cmd dans ce dossier.Read the full README ↗
SaaS de gestion des églises, ministères et communautés chrétiennes. Voir
docs/architecture/ pour l'architecture technique complète (STEP 01) et le
plan de développement par phase.
Sur cette machine, Node.js n'était pas installé au démarrage du projet : une version portable a été téléchargée dans
%LOCALAPPDATA%\nodejs-portable\node-v24.21.0-win-x64et ajoutée au PATH utilisateur. Ouvrez un nouveau terminal pour quenode/npmsoient reconnus directement ; sinon utilisez le chemin complet versnode.exe/npm.cmddans ce dossier.
npm install
npm run dev # http://localhost:3000
npm run dev # serveur de développement (Turbopack)
npm run build # build de production
npm run start # sert le build de production
npm run lint # ESLint
npm run format # Prettier (écrit les fichiers)
ChurchOS a un vrai projet Supabase déjà en ligne — db/schema.sql est ce schéma réel, adopté
tel quel comme source de vérité (voir docs/architecture/02-database-schema.md
pour le détail du pivot). Pas de Docker sur cette machine → Postgres local portable pour le
développement (voir db/local-postgres/README.md, notamment la
limitation pgvector) :
npm run db:local # démarre Postgres local sur :54329 (premier plan, Ctrl+C pour arrêter)
# dans un autre terminal :
npm run db:migrate:local # applique db/schema.sql en local
npm run db:seed # seed "Église Évangélique La Source"
npm run db:verify-rls # preuve d'isolation multi-tenant (RLS)
Contre le vrai projet Supabase : DATABASE_URL dans .env.local → sa chaîne de connexion, puis
appliquer db/schema.sql via le SQL Editor Supabase ou psql (déjà fait sur le projet réel en
théorie — voir plus haut).
Détail complet par phase : docs/architecture/07-sprint-plan.md.
| Phase | Statut |
|---|---|
| 1 Foundation, 2 Database | ✅ Livrées (schéma Supabase réel, RLS prouvé par npm run db:verify-rls, miroir Drizzle, seed) |
| 3 Authentication, 4 Organization (RBAC) | ✅ Livrées, vérifiées en conditions réelles |
| 5 Members, 6 Pastoral, 7 Ministries | ✅ Livrées, vérifiées en conditions réelles |
| 8 Events, 9 Finance, 10 Training | ✅ Livrées, vérifiées en conditions réelles |
| 11 Communication, 12 Documents & Resources, 13 Analytics | ✅ Livrées, vérifiées en conditions réelles |
| 14 Billing (Stripe) | 🚧 Architecture livrée ; création client + session Checkout vérifiées en direct. Reste : paiement de test (carte 4242…, à faire manuellement), synchronisation au retour, proratisation, annulation, facture |
| 15 ChurchOS AI | 🚧 Architecture livrée (tool-calling, filtrage par permission) ; vérification live bloquée par un 429 OpenAI (crédit manquant) |
Terminée : tableau de bord, menu latéral, Membres, Familles, Visiteurs, Groupes, Suivi pastoral,
Sujets de prière, Visites, Conseil pastoral, Ministères, Ouvriers, Services, Calendrier, Plannings,
Événements, Inscriptions, Présences, Statistiques (/analytics), et la page Vitrine (site marketing public).
/analytics)Page refaite selon la maquette : 12 cartes KPI, évolution des présences par catégorie, tranches
d'âge, répartition par groupe, activités par catégorie d'événement, dons (réservés à finance.view),
occupation des salles, top 5 des événements, nouveaux membres, statut des réservations et
engagement/communication. Sélecteur de période dans l'URL (?period=12m|6m|ytd) ; les variations
comparent à la période précédente de même durée (effectifs : depuis le début de la période,
approximation par date d'adhésion — le statut n'est pas historisé). Requêtes dans
features/analytics/queries/statistics.ts, vérifiées sur un Postgres 16 local avec des données de test ;
non testée sur les données réelles Supabase. Choix assumés : sans date de naissance, une présence est
comptée parmi les « Adultes » ; l'occupation d'une salle = jours avec réservation confirmée ÷ jours écoulés.
/platform)Vue réservée aux administrateurs de la plateforme (table platform_admins, distincte du rôle
SUPER_ADMIN qui reste limité à une organisation) : indicateurs globaux, liste/recherche des
églises, détail (usage, abonnement), catalogue des plans, journal des actions et suspension/réactivation (tracée dans audit_logs, bloque
l'accès de l'église via /suspended). Accès : appliquer la nouvelle table de db/schema.sql, puis
npm run db:grant-platform-admin -- [email protected]. Écrite et vérifiée par typecheck/lint
uniquement — à tester en conditions réelles.
Les pages Finance lisent de nouvelles colonnes (title, vendor_name, status, ...) et la table
financial_transaction_attachments + le bucket churchos-finance. Appliquer
db/migrations/2026-09-30-expense-form-fields.sql
sur Supabase AVANT de déployer (idempotent ; déjà inclus dans db/schema.sql). Sans finance.approve, une dépense est toujours créée « En attente ». Vérifiée sur un
Postgres 16 local (2 exécutions successives + requêtes de liste/KPI) ; l'upload Storage et
l'enregistrement via Supabase n'ont pas été testés en conditions réelles.
Le formulaire « Nouveau budget » ajoute aussi 4 colonnes à budgets :
db/migrations/2026-09-30-budget-form-fields.sql
(idempotent, inclus dans db/schema.sql) — le code ne les envoie que si elles sont renseignées.
Le champ « Ministère / Projet » ajoute budgets.ministry_id :
db/migrations/2026-09-30-budget-ministry.sql
(à appliquer aussi ; sans elle, créer un budget avec un ministère échoue).
Après une migration, si l'app affiche « Could not find the '…' column … in the schema cache », exécuter
notify pgrst, 'reload schema';dans le SQL Editor (les migrations ci-dessus le font déjà).
/finance/reports)Génération de rapports en PDF, Excel, JSON ou CSV (GET /api/finance/report?type=&format=&from=&to=&category=&fund=,
gardé par finance.view + reports.export) : vue d'ensemble, état des résultats, exécution budgétaire,
flux de trésorerie, budgets par ministère. Chaque génération est tracée dans audit_logs
(finance.report.generated) et alimente « Rapports récents » (un clic régénère le fichier, rien n'est
stocké). Les dépenses « en attente » sont comptées, les « rejetées » exclues. Aucune migration requise. Vérifié sur Postgres local (5 types × 4 formats, PDF relu en image) ;
le téléchargement navigateur authentifié n'a pas été testé en conditions réelles.
Paramètres > Église : téléversement du logo (PNG/JPEG/WebP, 2 Mo) dans le bucket public
churchos-logos, URL stockée dans organizations.logo_url. S'il existe, il remplace le logo
ChurchOS dans le menu latéral (bureau + mobile) et la pastille d'église de la barre du haut ; sans
logo, ChurchOS s'affiche. La Vitrine et les pages d'authentification gardent toujours le logo
ChurchOS. Migration : db/migrations/2026-10-01-organization-logos.sql
(idempotente, incluse dans db/schema.sql).
Profil > Avatar : 12 avatars prédéfinis (public/avatars/*.svg, un clic) ou photo personnelle
(PNG/JPEG/WebP, 2 Mo, bucket public churchos-avatars, dossier <user_id>/). Sans avatar, les
initiales s'affichent. Migration : db/migrations/2026-10-01-user-avatars.sql
(idempotente, incluse dans db/schema.sql).
churchos-member-photos, stockée dans people.photo_url,
retrait possible). Migration à appliquer : db/migrations/2026-10-02-member-photos.sql
(idempotente, incluse dans db/schema.sql).error.tsx global à (app) affiche un message au lieu de la page d'erreur
générique. Vérifié par typecheck/lint uniquement — à tester en conditions réelles.Selon la maquette : bannière (Matthieu 28:19) avec « Nouveau cours », 4 KPI (cours publiés,
apprenants actifs, certifications, taux de complétion), onglets Tous / En cours / Terminés / Mes
cours (+ recherche et tri dans l'URL), grille de cartes de cours (visuel courses.image_url,
modules, durée, progression personnelle, bouton Continuer/Commencer/Terminé) et colonne latérale
(Mon parcours en anneau, verset, cours récents, formateurs). « Mes cours » et « Mon parcours »
rapprochent l'utilisateur d'une fiche people par email (aucun lien direct compte ↔ personne dans
le schéma) ; sans correspondance ils restent vides. Écart avec la maquette : pas de « Parcours
de formation » ni d'onglet « Parcours » (aucune table correspondante) — le 3ᵉ KPI affiche les
certifications délivrées ; pas de badge « En vedette ». Aucune migration. Vérifié par
typecheck/lint uniquement — rendu à contrôler en conditions réelles.
Refonte selon la maquette : dialogue large en 3 sections (informations générales, détails, paramètres
et visibilité) avec aperçu en direct et image de couverture (PNG/JPEG/WebP, 2 Mo, bucket public
churchos-course-covers). Nouveaux champs de courses : catégorie, niveau, prérequis, date de
publication, co-formateurs, allow_enrollment, show_in_library. À la création, « Nombre de
modules » génère « Module 1 » … « Module N » (durée par module optionnelle, durée du cours = somme) ;
ces deux champs n'apparaissent pas à la modification (les modules se gèrent dans la fiche du cours).
Migrations à appliquer, dans l'ordre : 2026-10-03-course-form-fields.sql
puis 2026-10-04-course-categories.sql (idempotentes,
incluses dans db/schema.sql).
course_categories (bouton « Catégories » de la bannière :
ajout/suppression). Une organisation sans catégorie reçoit les 8 catégories par défaut à la première
ouverture ; supprimer une catégorie ne change pas les cours qui la portent (courses.category est un texte).enrollSelf) ; refusé côté serveur si le cours n'est pas publié ou si « Autoriser
l'inscription » est désactivé. Les gestionnaires (training.enroll) inscrivent toujours qui ils veulent.
Sans fiche people ayant le même email que le compte, l'auto-inscription est indisponible.Vérifié par typecheck/lint uniquement.
/training/certifications) et formulaire « Nouvelle certification »Nouvelle entrée « Certifications » sous Formations (le menu met désormais en surbrillance l'entrée la
plus spécifique). Page d'après la maquette : bannière (2 Timothée 3:14), 4 KPI (délivrées avec variation
vs année précédente, membres certifiés, programmes, taux de réussite = obtenues / total), onglets
Toutes / En cours / Obtenues / Expirées + recherche, tableau paginé (10 par page), répartition par
programme (anneau), statut (barres) et certifications récentes. Le formulaire (dialogue en 3 sections
avec aperçu du certificat) sert aussi sur la fiche d'un cours (programme figé). Migration à appliquer :
db/migrations/2026-10-05-certification-form-fields.sql
(idempotente, incluse dans db/schema.sql) : colonnes issuer, description, instructor_person_id,
status, visibility, file_path et bucket privé churchos-certificates (PDF/PNG/JPG, 5 Mo, envoi direct
navigateur → Storage, téléchargement par URL signée).
training.certify, training.manage) voient
tout ; les autres voient les certifications « toute l'église » et les leurs si « visibles par le membre ».notifications.person_id) — aucun écran ne les
affiche encore, et aucun email/SMS n'est envoyé.Vérifié par typecheck/lint/build uniquement.
/library)Entrée « Bibliothèque » sous Formations. Page d'après la maquette : bannière (Psaumes 119:105) avec « Catégories » (gestion) et « Ajouter une ressource », 4 KPI (ressources avec variation vs mois dernier, catégories, téléchargements, note moyenne), onglets par type (Livres, Études bibliques, Enseignements, Documents, Vidéos, Audios), recherche (titre, auteur, description, tags), filtres catégorie / format / tri
training.view pour consulter, training.manage pour ajouter/supprimer/gérer les
catégories ; les non-gestionnaires ne voient que les ressources publiées et « visibles par tous les membres ».
Migration à appliquer : db/migrations/2026-10-06-library.sql
(idempotente, incluse dans db/schema.sql) : tables library_categories, library_resources,
library_bookmarks, library_ratings, buckets churchos-library (privé, fichiers jusqu'à 100 Mo, URL
signées) et churchos-library-covers (public, 5 Mo). Les fichiers sont envoyés directement du navigateur vers
Storage. Supabase plafonne aussi la taille par fichier au niveau du projet (Storage > Settings) : l'augmenter
si 100 Mo est refusé.SUPER_ADMIN / CHURCH_OWNER, isAdmin) voient « Modifier » dans le menu ⋮ de chaque carte et sur la page de lecture ; le formulaire est pré-rempli, le fichier et la couverture ne sont remplacés que si on en choisit de nouveaux (couverture retirable), les anciens fichiers sont supprimés après coup. Le droit est revérifié côté serveur (updateResource). Les autres gestionnaires de formation peuvent ajouter et supprimer mais pas modifier.Formats : PDF et DOCX uniquement (formulaire, bucket Storage et filtres ; les types vidéo/audio ont été
retirés). Cliquer une carte ouvre /library/[id] : un PDF s'affiche dans la page (servi par
/api/library/[id]/file, relayé en flux depuis l'URL signée, depuis notre origine), un DOCX est converti
en HTML (mammoth) puis filtré par liste blanche (sanitize-html) ; au-delà de 20 Mo ou en cas d'échec de
lecture, un message invite à télécharger. « Télécharger » (carte et page de lecture) passe par la même route
(?download=1) et incrémente le compteur. Si 2026-10-06-library.sql a déjà été exécutée, appliquer aussi
2026-10-07-library-pdf-docx.sql (restreint le bucket).
Les mises en page très riches d'un DOCX (colonnes, zones de texte, en-têtes) ne sont pas reproduites à
l'identique par l'aperçu ; le téléchargement donne le fichier d'origine.
Vérifié par typecheck/lint/build uniquement.
Chaque bannière de page affiche un verset (Louis Segond) qui change chaque jour et correspond au
sujet de la page : src/lib/verses.ts contient une liste thématique par contexte (membres, familles,
visiteurs, groupes, pastoral, prière, visites, conseil pastoral, ministères, ouvriers, services,
plannings, événements, inscriptions, calendrier, présences, dons, finances, formations, certifications,
bibliothèque, tableau de bord, connexion, création d'église — 7 à 8 versets chacune).
getDailyVerse(contexte, slot?) choisit de façon déterministe (jour UTC = heure d'Abidjan, décalage propre
à chaque contexte) : même verset toute la journée pour tout le monde, rien à stocker. PageHero prend
verseContext ; les versets secondaires (cartes latérales de Services, Prière, Ouvriers, Formations)
utilisent slot = 1 pour différer du verset de la bannière. Les layouts de connexion/création d'église
appellent connection() pour ne pas figer le verset au build. Pour ajouter un verset, l'ajouter à la
liste du contexte concerné.
/communication) et « Nouvelle annonce »Page : bannière avec « Nouvelle annonce », 4 KPI (annonces publiées, messages envoyés, membres touchés,
taux de lecture moyen = lecteurs distincts / membres actifs, moyenné sur les annonces publiées), onglets
Toutes / Annonces / Messages / Brouillons / Planifiées, tableau unifié annonces + messages (vignette, type,
destinataires, date, statut, vues, actions Lire / Modifier / Supprimer), panneaux Répartition par type,
Destinataires et Annonces récentes. Les « vues » d'une annonce comptent les utilisateurs qui l'ont ouverte
(announcement_reads, une fois chacun) ; pour un message, les destinataires l'ayant lu. Une annonce
programmée dont l'heure est passée est affichée comme publiée (aucune tâche planifiée requise). Les anciens
onglets (Modèles, Composer, Historique) restent accessibles par les liens sous les onglets.
Formulaire (/communication/new, /communication/[id]/edit) : 4 sections (infos : titre, type, catégorie,
importance, contenu avec mise en forme gras / italique / ++souligné++ / listes / liens ; médias :
image 5 Mo, vidéo MP4 ou document PDF/DOCX 50 Mo, envoi direct navigateur → Storage ; destinataires : tous
ou groupes/ministères ; publication : immédiate, brouillon ou programmée) + aperçus de l'annonce et des
réseaux sociaux.
Publication sur les réseaux sociaux (Paramètres > Réseaux sociaux, /settings/social, admin/propriétaire) :
SOCIAL_TOKEN_KEY = openssl rand -base64 32, à ajouter sur Vercel)
puis stocké ; il ne quitte jamais le serveur. Facebook : publication immédiate ou programmation native (10 min
à 30 jours). Instagram : image obligatoire, pas de programmation (limite de l'API).announcement_social_posts) sans annuler l'annonce. Non testée contre les vraies API (aucun jeton ici).Migrations à appliquer : 2026-10-08-announcements-redesign.sql
et 2026-10-09-announcement-composer.sql (idempotentes,
incluses dans db/schema.sql).
/communication/messages) et Médias (/communication/media)Menu Communication : Annonces, Messages (SMS/Email), Médias. La page Messages suit la maquette : 3 KPI
(messages envoyés avec variation vs mois dernier, destinataires uniques, taux de délivrance), onglets Tous / SMS /
Email / Brouillons / Planifiés (+ lien Modèles, recherche), tableau paginé (titre, destinataires, canal, date, statut,
statistiques ✓ / ✗, menu Modifier / Envoyer maintenant / Dupliquer / Supprimer) et composeur « Nouveau message » en 3
étapes : destinataires (tous les membres actifs, groupes / ministères, liste personnalisée de personnes ; compteur de
destinataires joignables), contenu (modèle, compteur 160 caractères pour un SMS, variables {{prenom}} / {{nom}}),
planification (maintenant ou date + heure) et boutons Brouillon / Envoyer. Aucune migration : tout repose sur
les tables messages et notifications existantes (une ligne notifications par destinataire).
src/lib/sms/twilio.ts). Variables à ajouter : TWILIO_ACCOUNT_SID, TWILIO_AUTH_TOKEN,
TWILIO_FROM (ou TWILIO_MESSAGING_SERVICE_SID) et, si besoin, SMS_DEFAULT_COUNTRY_CODE (225 par défaut) pour
compléter les numéros locaux. Sans elles, la page affiche un bandeau et l'envoi est refusé (le message reste en brouillon).RESEND_API_KEY), comme avant.GET /api/cron/send-messages avec l'en-tête
Authorization: Bearer $CRON_SECRET (variable CRON_SECRET à définir) toutes les ~5 minutes (Vercel Cron ou autre) ; sans
cela, un message planifié reste en attente (« Envoyer maintenant » le déclenche à la main). L'envoi est protégé contre le double envoi.Vérifié par typecheck/lint/build uniquement — jamais essayé avec de vrais comptes Twilio / Resend.
/communication/media)D'après la maquette : 4 KPI (photos, vidéos, audios, documents, avec variation vs mois dernier) + stockage utilisé
(sur 10 Go, constante MEDIA_STORAGE_QUOTA_BYTES), onglets Tous / Photos / Vidéos / Audios / Documents + recherche
(titre, tags), grille de 12 médias paginée et panneau de détail (aperçu, téléchargement, partage = copie du lien,
suppression, informations, tags modifiables, titre modifiable).
youtube.com/@nom, /channel/UC… ou /c/nom) ; elle est stockée dans
media_youtube_channels. Les 150 dernières vidéos publiques sont lues via l'API YouTube Data v3 (playlist « uploads », durée et vues
comprises), mises en cache 15 min, et lues dans un lecteur intégré (youtube-nocookie). Variable à ajouter : YOUTUBE_API_KEY
(clé API « YouTube Data API v3 » créée dans Google Cloud ; aucune authentification OAuth requise, la chaîne doit être publique).
Le compteur « Vidéos » utilise le total de la chaîne.churchos-media). Les images et documents joints aux annonces apparaissent aussi (lecture seule) ; les vidéos d'annonce ne sont pas listées.communication.view pour consulter, communication.manage pour ajouter / modifier / supprimer, administrateur pour relier la chaîne.db/migrations/2026-10-10-media-library.sql (idempotente, incluse dans
db/schema.sql et 2026-10-all-migrations.sql) : tables media_items, media_youtube_channels, bucket churchos-media.Vérifié par typecheck/lint/build uniquement — jamais essayé avec une vraie clé YouTube ni un vrai bucket.
/resources)Refonte d'après la maquette : bannière (1 Corinthiens 14:40, contexte de verset resources), 4 KPI (salles et équipements avec
le nombre ajouté ce mois, réservations ce mois avec variation %, taux d'occupation avec variation en points), onglets
Salles / Équipements / Réservations / Calendrier (+ recherche dans l'URL), bouton bleu à menu Nouvelle salle / Nouvel équipement.
metadata.photos, capacité, localisation,
type, description, équipements affectés avec « Voir tout (n) », 3 prochaines réservations avec statut, boutons Modifier / Réserver cette salle).
Statut affiché « Réservée » quand une réservation active (en attente / confirmée) couvre l'instant présent, « En maintenance » si la salle l'est.?room=).?month=YYYY-MM) des réservations non annulées./resources/new-room (4 sections : infos générales ; disponibilité et paramètres — statut, réservable par,
autoriser les réservations, validation requise, calendrier public ; équipements cochables ; photos) et /resources/new-equipment (5 sections : infos ; détails —
marque, modèle, n° de série, état, date et valeur d'achat ; affectation — salle et responsable ; garantie, fournisseur, référence facture ; photo et documents),
chacun avec aperçu en direct à droite, « Enregistrer en brouillon » (statut draft, visible des seuls gestionnaires, hors indicateurs, non réservable) et
« Créer ». Modification : /resources/[id]/edit (même formulaire). Le fil d'Ariane affiche le groupe du menu (« Ressources › Salles & équipements › Nouvelle salle »).db/migrations/2026-10-11-resources-forms.sql (idempotente, incluse dans db/schema.sql et
2026-10-all-migrations.sql ; testée deux fois sur Postgres 16) : colonnes de resources (capacité, type de salle, équipements, réservable par, options de réservation,
notes, catégorie, marque, modèle, série, état, achat, salle d'affectation, responsable, garantie, fournisseur, facture, photos, documents), statut draft, et deux buckets :
(photos, public, 5 Mo) et (documents PDF/JPG/PNG, privé, URL signée, 5 Mo). Les valeurs déjà rangées dans
(capacité, type, catégorie, salle) sont reprises. Sans la migration, les pages affichent « Mise à jour de la base de données requise ».Vérifié par typecheck/lint/build uniquement — rendu à contrôler en conditions réelles.
« Créer un utilisateur » (prénom, nom, email, rôle, fonction) remplace l'ancienne invitation par email. POST /api/organizations/members/create (permission
settings.manage, client admin Supabase côté serveur uniquement) génère un mot de passe aléatoire (14 caractères, CSPRNG, conforme à la politique :
majuscule, minuscule, chiffre, caractère spécial ; caractères ambigus 0/O/1/l/I exclus — src/lib/auth/password.ts), crée le compte (email confirmé) et le
rattache à l'église avec son rôle. L'administrateur voit une seule fois l'identifiant et le mot de passe (boutons Copier) ; ils sont aussi envoyés par
email à l'utilisateur si RESEND_API_KEY est configurée. Le mot de passe n'est jamais stocké en clair. À sa première connexion (/login → son église),
l'utilisateur est redirigé vers /reset-password/update et doit choisir un nouveau mot de passe (drapeau user_metadata.must_change_password, levé par
updatePassword). Si l'email a déjà un compte ChurchOS (autre église), il est simplement rattaché à cette église sans toucher à son mot de passe. En cas
d'échec du rattachement, le compte tout juste créé est supprimé. Pas de migration. Vérifié par typecheck/lint/build uniquement — jamais essayé contre un vrai
projet Supabase. Non fait : bouton « Réinitialiser le mot de passe » d'un utilisateur existant (l'utilisateur peut passer par « Mot de passe oublié »).
/)Animations en CSS pur + un petit composant Reveal (IntersectionObserver), sans dépendance : entrée échelonnée du hero (badge, titre au mot « ChurchOS » en dégradé
animé, texte, boutons), halos lumineux flottants, image de l'église en lent zoom avec trois cartes d'interface qui flottent, apparition au défilement des modules,
fonctionnalités (qui arrivent de la gauche), aperçu du tableau de bord (de la droite, avec l'aperçu mobile flottant), cartes « pourquoi », tarifs (le prix
se ré-anime au changement mensuel / annuel), témoignages (étoiles animées au survol) ; FAQ à ouverture animée ; bannière finale avec reflet et bouton pulsant ;
barre de navigation qui prend de l'ombre au défilement, soulignement animé des liens, menu mobile qui glisse ; défilement doux vers les ancres.
prefers-reduced-motion désactive toutes les animations, et sans JavaScript tout reste visible (<noscript>). Les keyframes sont dans tailwind.config.ts,
les classes .reveal dans globals.css. Vérifié dans Chromium (Playwright) : entrée du hero, révélation de toutes les sections au défilement, ombre de la barre,
mode « mouvement réduit ».
Correction au passage : la palette blue de Tailwind était entièrement remplacée par la teinte de marque, donc bg-blue-100, text-blue-600… n'existaient pas
(pastilles et icônes bleues sans couleur dans toute l'application) ; la palette standard est rétablie, bg-blue gardant la teinte de marque.
src/lib/navigation.ts porte la permission que vérifie sa page (permission) ; le layout résout les permissions du membre
(getAllowedNavHrefs) et le menu (bureau, mobile, menu du compte) n'affiche que les modules autorisés ; une section sans entrée disparaît avec son titre.
Tableau de bord, ChurchOS AI, Profil et Notifications restent visibles par tous (l'IA filtre elle-même ses outils par permission) ; les pages restent protégées côté
serveur. Exemples : un MEMBER voit 14 entrées, un FINANCE_MANAGER 14, un administrateur 40. Les permissions étant lues à chaque requête, un changement de rôle
agit dès le prochain chargement de page. Limite : le Tableau de bord vérifie members.view ; un rôle sans cette permission voit « accès refusé » sur cette page.updateMemberRole vérifie que le membre et le rôle sont de
l'église, interdit de modifier son propre rôle, réserve l'attribution / le retrait d'un rôle d'administrateur aux administrateurs, empêche de rétrograder le dernier
administrateur, et ajoute le nouveau rôle avant de retirer les anciens (jamais de membre sans rôle). Confirmation « Rôle mis à jour » affichée sous la liste.Le catalogue passe de 61 à 70 permissions : certifications, bibliothèque, messages SMS/Email, médias, salles et équipements ont désormais leurs propres permissions
(avant, ils dépendaient de training.*, communication.* et resources.*) : certifications.view, library.view / library.manage, messages.view / messages.send,
media.view / media.manage, rooms.view / rooms.manage / rooms.reserve, equipment.view / equipment.manage / equipment.reserve. Les pages, actions serveur, le menu
et la matrice des rôles les utilisent ; la matrice affiche un libellé pour chaque module. Annonces : communication.* (sans communication.send, remplacée par messages.send) ;
cours : training.*. Dans Salles & équipements, chaque onglet, KPI, bouton et réservation respecte le droit du type concerné (un rôle qui n'a que equipment.* ne voit
pas les salles, et inversement ; les brouillons ne sont visibles que de qui gère le type).
Migration à appliquer : db/migrations/2026-10-12-permissions-modules.sql (idempotente, incluse dans db/schema.sql et
2026-10-all-migrations.sql, testée deux fois sur Postgres 16) : ajoute les nouvelles permissions, reprend les droits déjà accordés (un rôle qui avait training.view reçoit certifications.view
et library.view, communication.view → messages.view + media.view, resources.* → rooms.* + equipment.*, etc.) puis supprime communication.send et resources.*. À exécuter AVANT
de déployer : sans elle, les rôles personnalisés perdent l'accès à ces modules (les administrateurs gardent tout) et la matrice n'affiche pas les nouvelles lignes.
Les pages /training, /training/certifications, /library, /communication (et ses pages de
formulaire) et /settings/social détectent une base sans la migration attendue (erreur Postgres
« colonne / table inexistante », src/lib/db/schema-guard.ts) et affichent « Mise à jour de la base de
données requise » avec le fichier à exécuter, au lieu de l'erreur React #441 (message masqué en
production). Le fichier db/migrations/2026-10-all-migrations.sql regroupe les migrations du 3 au
9 octobre (formulaire de cours, catégories de cours, certifications, bibliothèque, annonces) : à
exécuter une fois dans le SQL Editor Supabase (idempotent) ; 2026-10-07-library-pdf-docx.sql reste
à part si la bibliothèque avait été créée avant la restriction PDF/DOCX. YouTube a été retiré du
formulaire d'annonce (seuls Facebook, Instagram et le partage WhatsApp restent).
| Quoi | Où | Pour |
|---|---|---|
db/migrations/2026-10-all-migrations.sql (idempotent) | SQL Editor Supabase | Cours, catégories de cours, certifications, bibliothèque, annonces, médias, salles & équipements, permissions par module (3 au 12 oct.) |
db/migrations/2026-10-07-library-pdf-docx.sql | SQL Editor Supabase | Seulement si 2026-10-06-library.sql avait été exécutée avant la restriction PDF/DOCX |
SOCIAL_TOKEN_KEY (openssl rand -base64 32) | Variables Vercel | Connecter Facebook / Instagram (Paramètres > Réseaux sociaux) |
YOUTUBE_API_KEY + migration 2026-10-10-media-library.sql (+ 2026-10-11-resources-forms.sql pour Salles & équipements) | Variables Vercel / SQL Editor | Page Médias (vidéos de la chaîne YouTube, téléversements) |
TWILIO_*, CRON_SECRET + appel périodique de /api/cron/send-messages | Variables Vercel / planificateur | Envoi de SMS et messages planifiés |
Migrations plus anciennes (mai–sept.) : db/migrations/*.sql par ordre de date, toutes incluses dans
db/schema.sql. Une page dont la migration manque affiche un message explicite (voir ci-dessus).
/settings/profile) : écrite (infos personnelles, préférences, changement de mot de passe avec réauthentification), vérifiée par typecheck/lint uniquement — à tester en conditions réelles.lib/feature-flags/, alertes de paiement en retard, publication YouTube (l'API ne
permet pas de publier du texte), publication WhatsApp automatique (pas d'API vers un groupe).churchos-resourceschurchos-resource-docsmetadata