cd apps/server
npm install
npx prisma migrate dev
npm run seed
npm run dev # http://localhost:3000Le plus simple pour héberger soi-même : un docker-compose.yml (racine du dépôt)
lance le serveur et une base PostgreSQL, avec l'ordonnanceur de crons intégré.
cp .env.docker.example .env # puis renseignez au moins AUTH_SECRET
# AUTH_SECRET : openssl rand -base64 48 (obligatoire)
# DATA_ENC_KEY : openssl rand -base64 32 (recommandé)
# POLICY_SIGNING_SEED / CRON_SECRET : recommandés
docker compose up -d # build + démarre ; http://localhost:3000Le conteneur applique le schéma (prisma db push, ré-essayé jusqu'à ce que la
base réponde) puis démarre. Données Postgres persistées dans le volume
kidora-db. La rétention, la détection d'appareils hors-ligne et les rapports
hebdo tournent automatiquement (grâce au CRON_SECRET).
⚠️ Non encore construit en CI : l'image suit le schéma standard Next.js + Prisma (openssl installé pour le moteur de requête). Signalez tout souci de build. Derrière un reverse proxy TLS pour l'accès distant (HTTPS requis horslocalhostpour la PWA et le push).
Le bouton clone le dépôt, fixe le dossier racine sur apps/server, demande les
3 variables d'env, puis déploie. Le buildCommand (npm run vercel-build)
crée le schéma Postgres automatiquement (prisma db push) au premier build —
rien d'autre à faire que de provisionner une base et de la coller dans
DATABASE_URL.
Import manuel (dépôt existant) : Vercel → Add New… → Project → importez
kidora→ Root Directory =apps/server→ ajoutez les variables d'env → Deploy.
Le serveur Next.js est prêt pour Vercel. SQLite ne persiste pas en serverless : passez à PostgreSQL (Neon, via le Vercel Marketplace).
Aucun changement de code. Le choix de la base est automatique d'après
DATABASE_URL:
file:…→ SQLite (driverbetter-sqlite3) — défaut dev.postgres:///postgresql://→ PostgreSQL (driverpg).
src/lib/prisma.tssélectionne l'adaptateur au runtime, et le scriptscripts/select-db-provider.mjs(lancé parpostinstall/prebuild) aligne leproviderdu schéma Prisma sur la cible avantprisma generate(le dialecte SQL est figé à la génération etproviderne peut pas être unenv()).
- Vercel → Storage → Neon Postgres (ou
npx create-db). - Récupérez
DATABASE_URL(ajoutez?sslmode=requiresi nécessaire).
| Clé | Valeur | Portée |
|---|---|---|
DATABASE_URL |
chaîne Postgres | Build + Runtime |
AUTH_SECRET |
secret aléatoire (48+ octets) | Runtime |
DATABASE_PROVIDER |
(optionnel) postgresql pour forcer le dialecte au build si DATABASE_URL n'est pas dispo au build |
Build |
DATABASE_URLdoit être présente au build :prebuildgénère le client Prisma pour le bon dialecte. Sur Vercel les variables d'env sont dispo au build par défaut. Sinon, posezDATABASE_PROVIDER=postgresql(override explicite).
Vérifier la configuration : une fois déployé, ouvrez
/status— une liste de contrôle (base de données, secrets, push, e-mails, HTTPS…) qui indique ce qui reste à configurer, sans afficher aucune valeur secrète. Version JSON :/api/status.
Le buildCommand de vercel.json est npm run vercel-build
(scripts/vercel-build.mjs) : à chaque build, si DATABASE_URL est
configurée, Prisma synchronise le schéma sur la base (prisma db push,
idempotent) puis l'app est compilée. Aucune étape manuelle — il suffit que
DATABASE_URL soit présente au build (cas par défaut sur Vercel).
Robustesse : si
DATABASE_URLn'est pas définie, le build n'échoue plus — il sautedb:push(avec un avertissement clair dans les logs) et déploie quand même le site. Les pages liées à la base échoueront à l'exécution, mais vous obtenez un déploiement (et un message d'erreur explicite) au lieu d'un 404NOT_FOUNDopaque dû à un build planté. SiDATABASE_URLest définie mais que le push échoue (identifiants/réseau), le build échoue volontairement — c'est une vraie erreur à corriger.
Premier compte : une installation réelle ne crée aucun identifiant par défaut
(pas de compte de démonstration connu en production). Ouvrez l'application et
créez votre compte sur /register.
Données de démonstration (évaluation seulement, jamais sur une base réelle) :
# Le script EFFACE les données puis insère un compte de démo. Il refuse de
# s'exécuter en production ou sur une base non vide sans opt-in explicite.
cd apps/server && SEED_DEMO=1 SEED_FORCE=1 npm run seedLe seed cible SQLite (données d'exemple) ; en production, créez plutôt votre compte via
/register.
Les migrations du dépôt sont en dialecte SQLite ; en prod on utilise
db push(pas d'historique de migration). Pour un baseline de migrations Postgres dédié :prisma migrate diffcontre la base cible (amélioration future).
Via le bouton ci-dessus, l'import Vercel (Git intégré : chaque push redéploie), ou la CLI :
cd apps/server
vercel deploy --prod # npm i -g vercel ; root = apps/serverUn 404 NOT_FOUND servi par Server: Vercel (en-tête X-Vercel-Error: NOT_FOUND)
n'est pas le 404 de l'app : le nom de domaine ne pointe vers aucun
déploiement. Causes habituelles et correctifs :
- Aucun déploiement production réussi. Le domaine de prod n'est attribué
qu'au dernier déploiement production (les previews ont des URLs
*-git-<branche>/*-<hash>). Vérifiez Deployments : s'ils sont tous en Error, ouvrez les Build Logs. No Next.js version detecteddans les logs → Root Directory mal réglé. Settings → General → Root Directory =apps/server.Environment variable not found: DATABASE_URL(ou connexion DB refusée) → ajoutezDATABASE_URL(Postgres joignable) etAUTH_SECRETdans l'env Production, puis redéployez. (Depuis le build robuste, l'absence deDATABASE_URLne plante plus le build — mais une URL invalide, si.)- Mauvaise branche de production. Settings → Git → Production Branch =
main. - Domaine non attribué. Settings → Domains : vérifiez qu'un domaine est bien rattaché à la Production.
En monorepo, le projet Vercel doit cibler
apps/server(lepackage.jsoncontenant Next.js). Le bouton « Deploy » du README pré-règle ce dossier ; un import manuel doit le régler à la main.
Si l'URL répond 302 vers https://vercel.com/sso-api?... (et pose un cookie
_vercel_sso_nonce), le déploiement fonctionne mais il est privé : la
Protection de Déploiement Vercel (Vercel Authentication) est active, donc
seuls les membres de l'équipe connectés y accèdent — le public est renvoyé vers
la connexion Vercel.
➡️ Correctif (rend l'app publique) : Project → Settings → Deployment
Protection → Vercel Authentication → mettre sur Disabled (ou Only Preview
Deployments pour ne protéger que les previews). La prod devient alors publique
sur https://<project>-<team>.vercel.app.
Vercel attribue plusieurs domaines *.vercel.app ; un alias auto-généré
(p. ex. monprojet-<mot>.vercel.app) peut avoir été retiré (→ 404) alors que
le domaine canonique monprojet-<team>.vercel.app fonctionne. Utilisez l'URL
listée dans Settings → Domains (rubrique Production), ou ré-ajoutez le
domaine voulu / ajoutez un domaine personnalisé et rattachez-le à la
Production. *.vercel.app visé n'appartient pas à un
autre projet (les noms *.vercel.app courts sont uniques globalement).
Chaque semaine, Kidora peut envoyer à chaque parent un résumé d'usage de sa
famille (temps d'écran, top apps, web, alertes). Opt-out par parent dans
Paramètres › Notifications (champ Parent.weeklyReportEmail, activé par défaut).
| Clé | Exemple |
|---|---|
SMTP_HOST |
smtp.sendgrid.net |
SMTP_PORT |
587 (ou 465) |
SMTP_SECURE |
false (true pour 465) |
SMTP_USER / SMTP_PASS |
identifiants SMTP |
MAIL_FROM |
Kidora <no-reply@kidora.app> |
APP_URL |
https://kidora.example.com (lien dans l'email) |
Sans SMTP_HOST, l'envoi est désactivé et le cron répond configured:false
(il indique tout de même combien de parents seraient notifiés).
L'endpoint GET /api/cron/reports envoie les emails. apps/server/vercel.json
le planifie chaque lundi 8h :
{ "crons": [{ "path": "/api/cron/reports", "schedule": "0 8 * * 1" }] }Protégez-le avec CRON_SECRET (Vercel Cron envoie automatiquement
Authorization: Bearer $CRON_SECRET). Pour un autre hébergeur, planifiez un
simple appel HTTP :
curl -H "Authorization: Bearer $CRON_SECRET" https://kidora.example.com/api/cron/reportsTest manuel (sans envoi réel) : ?dryRun=1 — …/api/cron/reports?dryRun=1&days=7.
En dev (hors production) l'endpoint est accessible sans secret.
vercel.json planifie aussi deux crons de fond (mêmes règles d'auth CRON_SECRET) :
{ "crons": [
{ "path": "/api/cron/cleanup", "schedule": "0 4 * * *" },
{ "path": "/api/cron/offline-check", "schedule": "0 * * * *" }
] }/api/cron/cleanup(quotidien) — purge la télémétrie plus ancienne queRETENTION_DAYS(défaut 90). Prévisualiser :?dryRun=1(+?days=pour tester)./api/cron/offline-check(horaire) — alerte le parent quand un appareil ne répond plus depuisOFFLINE_ALERT_HOURS(défaut 12).?dryRun=1/?hours=.
Auto-hébergement (hors Vercel) : pas besoin de configurer un cron externe. Au démarrage (
next start), un ordonnanceur intégré (instrumentation.ts) déclenche ces routes automatiquement — rétention (quotidienne), appareils hors-ligne (horaire) et rapports hebdo — dès qu'unCRON_SECRETest défini (généré parinstall.sh). Il ne s'active jamais sur Vercel (où Vercel Cron s'en charge) ni sur l'Edge.
Pointez l'agent sur l'URL déployée :
node agent.js --token <JETON> --server https://kidora.exemple.com
# démarrage auto :
powershell -File install-agent.ps1 -Token <JETON> -Server https://kidora.exemple.comcd apps/mobile
eas build --platform android # dev build natif (modules enforcement)Configurez extra.defaultServer dans app.json sur l'URL de production.