HF-OS · Socle technique & mise en prod
HF-OS : socle Next.js 16 + Payload 3 déployé, connexion admin par Google
Contexte / le besoin
HF-OS, c'est le mini-ERP interne « Haute Fidélité » : éditorial, régie pub et agents IA, à terme. L'objectif de cette étape était volontairement borné : poser le socle technique et le déployer, avec un seul critère de réussite — « un socle déployé où je me connecte en admin via Google ». Pas de collections métier, juste la coquille.
Décisions d'archi déjà prises en entrée : application unique Next.js + Payload 3 (admin /admin, API /api et dashboard dans la même app), adaptateur PostgreSQL, déploiement en process persistant, secrets en variables d'environnement, et une nav vide (Éditorial / Régie / IA / Paramètres) avec barre latérale contextuelle.
Ce qui a été fait
8 juin 2026 — le scaffold (PR #1)
- App Next.js + Payload 3.85 +
@payloadcms/db-postgres, en pnpm. - Collection
Usersen auth uniquement (le minimum Payload), plus un champname. - Coquille du dashboard : barre principale (Éditorial / Régie / IA / Paramètres) + barre latérale contextuelle qui change selon la section, pages « à venir ».
- Auth Google SSO maison : routes
/oauth/google(init + state anti-CSRF) et/oauth/google/callback, contrôle de la liste blancheAUTHORIZED_EMAILS, bouton « Se connecter avec Google » sur la landing et l'écran admin. - Outillage : Dockerfile (cible Scaleway Containers) + alternatives
render.yaml/railway.json, CI GitHub Actions (install + lint + typecheck + build), Renovate,.env.exampledocumenté, README avec runbook.
8–10 juin 2026 — la mise en prod (PR #2 à #5)
- Base PostgreSQL managée Scaleway (PG 17, standalone, le plus petit nœud).
- Déploiement de l'app sur Render via Blueprint (
render.yaml), branché sur la base Scaleway. - Client OAuth Google créé (Google Cloud Console), redirect URIs dev + prod.
- Migrations Payload générées et branchées en
prodMigrationspour créer le schéma au démarrage. - MCP Render connecté à Claude Code pour piloter les déploiements sans copier-coller.
Décisions et alternatives écartées
- Next 16.2.6, pas 15.5.x. La cible initiale était « Next 15.5.x », mais les
peerDependenciesde@payloadcms/next@3.85donnent>=15.4.11 <15.5.0 || >=16.2.6 <17.0.0: 15.5.x n'est pas supporté. D'abord épinglé 15.4.11, puis basculé sur 16.2.6 — le plus à jour, et ce qu'utilise le template officiel Payload 3.85. (Écarté : 15.5.x, impossible ; 15.4.11, valable mais moins à jour.) - Render plutôt que Scaleway Containers pour démarrer. La cible « propre » reste Scaleway (Dockerfile + workflow conservés dans le repo), mais Render est plus rapide à brancher pour un premier live. (Écarté pour l'instant : Scaleway Containers ; Railway gardé en alternative.)
- Réutiliser la base Scaleway au lieu d'une base managée Render (évite de payer deux fois ;
render.yamladapté pour pointer dessus). - SSO Google maison (routes custom + cookie de session Payload obtenu en régénérant un mot de passe interne puis
payload.login) plutôt qu'un plugin d'auth.
Galères et comment on a réglé
La mise en prod a enchaîné cinq blocages, réglés un par un (les logs Render ont servi de boussole) :
self-signed certificate(SSL Scaleway) : la base managée présente un certif non vérifiable. Réglé en passantDATABASE_URIdesslmode=requireàsslmode=no-verify(connexion toujours chiffrée, vérification du certif désactivée).permission denied for database "hf_os": l'utilisateur Postgres n'avait aucun droit sur la base créée à part. Réglé en accordant la permission « Tout » surhf_osdans la console Scaleway.redirect_uri_mismatch(Google) : l'URL de callback de prod n'était pas déclarée. Réglé en ajoutanthttps://<domaine-prod>/oauth/google/callbackdans le client OAuth.oauth_token(échange du code échoue) : diagnostic à l'aveugle au départ → ajout de logs détaillés dans le callback (PR #3) pour voir la réponse exacte de Google. Résolu après vérification des identifiants et de la redirect URI.error=session→relation "users" does not exist: la cause racine, confirmée par le code de l'adaptateur — en production Payload ne synchronise pas le schéma automatiquement (le push dev est gated surNODE_ENV !== 'production'), il ne joue que des migrations. On a généré la migration initiale (payload migrate:create, testée sur une base vierge locale → 8 tables), et branchéprodMigrationssur l'adaptateur (PR #4). Au boot suivant :Migrating: 20260610_203130_initial→ tables créées → connexion OK.
Détail utile : le « Not Found » initial sur *.onrender.com n'était pas un bug — juste la réponse de Render pour un sous-domaine pas encore attribué.
Résultat
- App en ligne sur son sous-domaine Render (URL de prod gardée privée), connexion admin via Google fonctionnelle (compte admin créé automatiquement à la première connexion d'un email whitelisté). Objectif de l'étape atteint.
- 5 PR mergées sur
main, CI verte à chaque fois ; autoDeploy Render actif (chaque merge redéploie). - Coût d'exploitation : ordre de grandeur ~40 €/mois (Render ~7 $ + base Scaleway ~32 €), la base étant le gros poste.
- Stack figée : Payload 3.85, Next 16.2.6, React 19.2, pnpm ; secrets en placeholders (DB, Google, Brevo/Qonto/Telegram prévus mais vides).
Suite
- Pilotage en boucle : MCP Render branché → diagnostiquer/redéployer sans manip manuelle (à valider en nouvelle session).
- Optimiser le coût : migrer la base vers une option moins chère (poste dominant).
- Construire les vraies sections : passer de la coquille aux collections métier (Éditorial, Régie, IA).
- Éventuel : bascule du front sur Vercel, vérification SSL stricte (certif CA Scaleway) au lieu de
no-verify.