Aller au contenu

Backend Go et PocketBase

Le backend étend PocketBase avec une API Go tout en gardant les règles métier indépendantes du framework. main.go constitue la racine de composition et démarre les repositories, services, handlers et workers.

Architecture interne du backend Le Clos des Eucalyptus

Dossier Responsabilité
domain/<feature> entités, ports, services et erreurs stables
api/ middleware, handlers HTTP, validation et autorisation
dto/ corps et réponses propres au transport HTTP
infra/pb/ repositories PocketBase
infra/<provider>/ SMTP, IA, médias, iCalendar et temps réel
migrations/ historique versionné du schéma PocketBase
seeds/ données locales compilées uniquement avec le tag dev
tests/domain/ tests unitaires des règles métier
tests/integration/ migrations, repositories et API avec PocketBase isolé
docs/openapi.yaml contrat HTTP public
  1. Modélisez l’entité, la commande et les erreurs dans domain/<feature>.
  2. Définissez les ports minimaux nécessaires au service.
  3. Testez le service avec des implémentations mémoire ou factices.
  4. Implémentez le repository sous infra/.
  5. Ajoutez les DTO sans réutiliser automatiquement les modèles PocketBase.
  6. Créez un handler mince qui valide, autorise, appelle le service et mappe les erreurs.
  7. Assemblez les dépendances dans main.go.
  8. Ajoutez le contrat OpenAPI et les tests d’intégration.

Un handler ne contient pas de calcul tarifaire, de transition éditoriale ou de règle de rôle complexe. Un service de domaine ne reçoit pas *core.App, *core.RequestEvent ou un record PocketBase.

Le domaine expose des erreurs que l’API traduit vers des statuts et corps prévisibles. Distinguez :

  • entrée invalide : 400 ou 422 selon le contrat ;
  • authentification absente ou invalide : 401 ;
  • rôle insuffisant : 403 ;
  • ressource absente : 404 ;
  • conflit de version ou d’état : 409 ;
  • erreur inattendue : 500 sans détail interne.

Ne renvoyez pas au client le message brut d’un fournisseur, d’une base ou d’une erreur Go.

Les repositories traduisent les records en entités et inversement. Ils centralisent les noms de collections, filtres et relations. Le domaine ne dépend pas d’un identifiant ou d’un hook propre à PocketBase, sauf si cette notion appartient réellement au métier.

Les opérations multi-étapes qui doivent rester cohérentes utilisent les capacités transactionnelles appropriées. Une création partielle ne doit pas laisser des traductions ou relations orphelines.

Toute modification de collection passe par migrations/ et doit fonctionner sur une base existante.

  • utilisez un identifiant et un ordre déterministes conformes au dépôt ;
  • rendez les nouvelles colonnes compatibles avec les records actuels ;
  • remplissez ou transformez les données avant d’imposer une contrainte ;
  • prévoyez le retour arrière lorsqu’il n’entraîne pas de perte ;
  • évitez une suppression irréversible dans le même déploiement qu’un remplacement ;
  • testez la migration réelle dans tests/integration ;
  • vérifiez le seed après migration.

Pour un renommage, préférez ajouter, recopier, déployer les consommateurs puis supprimer dans une version ultérieure.

Les contenus localisés utilisent la collection translations, indépendante du schéma des entités. Les repositories résolvent la locale demandée, appliquent le fallback vers la locale par défaut et renvoient une forme cohérente au domaine.

Une écriture back-office valide toutes les locales actives sans exiger qu’une traduction secondaire soit remplie. Le code de locale reçu doit exister et être activé.

Le flux back-office combine mot de passe, challenge à usage unique et TOTP obligatoire. Les rôles sont limités à admin, manager et author. Les handlers appliquent l’autorisation même si le frontend masque l’action.

Le secret TOTP chiffré dépend de HARMONY_TOTP_ENCRYPTION_KEY. En production, fournissez une valeur stable d’au moins 32 caractères. La changer invalide les secrets déjà chiffrés.

Les URL iCalendar contiennent souvent un jeton. Elles sont chiffrées avec HARMONY_CALENDAR_ENCRYPTION_KEY. Le worker examine les sources toutes les cinq minutes et respecte leur intervalle configuré entre quinze minutes et vingt-quatre heures.

La prévisualisation valide le feed et découvre les libellés avant la création. La synchronisation associe ces libellés aux appartements Le Clos des Eucalyptus et produit des blocs de disponibilité.

Les producteurs métier créent des notifications durables. Les adaptateurs peuvent ensuite envoyer un e-mail ou publier un événement temps réel. Une panne SMTP ne doit pas effacer la trace métier ; le statut d’acheminement reste consultable et relançable.

Le frontend consomme les notifications temps réel par un endpoint SSE BFF. Tout proxy devant ce flux doit désactiver le buffering et autoriser une connexion longue.

Le domaine média possède les imports, variantes, usages et galeries. Les limites de taille, formats et nombre d’éléments sont validées avant le traitement. Les fichiers ne sont jamais servis par un chemin arbitraire fourni par l’utilisateur : les routes de fichier valident la forme attendue.

L’IA est désactivée par défaut. domain/ai.Gateway reste indépendant du fournisseur ; les clés, modèles, appels HTTP et réponses brutes vivent sous infra/ai.

Chaque tentative crée un audit ai_runs avant l’appel puis le termine en succès ou échec. L’audit conserve les métadonnées, hash, latence et usage, jamais la clé, le prompt complet, le texte source ou la réponse générée. Les propositions de traduction restent soumises à validation humaine.

Fenêtre de terminal
make fmt-check vet staticcheck
make test-unit
make test-integration
make contract
make build
make verify

make verify exécute cette chaîne complète avec des délais distincts pour les tests unitaires et d’intégration. Les tests d’intégration utilisent une base isolée et les migrations réelles.