Odoo 18 sur Docker
1. Quoi ? — Définition et contexte
Section intitulée « 1. Quoi ? — Définition et contexte »Odoo est un ERP (Enterprise Resource Planning) open-source qui centralise les données métier dans une base unique. Cette instance Odoo 18 Community tourne en Docker, sur sa propre PostgreSQL dédiée, avec trois modules custom qui adaptent l’ERP au workflow technique : sync GitHub, télémétrie Claude Code, et expériences web pour le site.
Modules en place
Section intitulée « Modules en place »Modules natifs activés :
| Module | Usage |
|---|---|
| Project | Projets et tâches |
| Timesheets | account.analytic.line — alimenté par TimeTrackr |
| Website | Page d’atterrissage et hub |
| CRM | Leads et conversion (à étendre) |
Modules custom maintenus dans odoo-stack/addons/ :
| Module | Version | Usage |
|---|---|---|
project_github_sync | v18.0.5.6.0 | Sync GitHub ↔ tâches + télémétrie Claude Code + double-triage AI + estimation |
website_experiments | v18.0.1.1.0 | Snippets interactifs (Flip Display, Glass Splat) pour le Website Builder |
powered_by_odoo_remove | tiers | Retire le branding “Powered by Odoo” sur les pages publiques |
Vision métier
Section intitulée « Vision métier »Pour comprendre pourquoi Odoo a été choisi parmi les alternatives, voir Pourquoi Odoo.
2. Pourquoi ? — Enjeux et motivations
Section intitulée « 2. Pourquoi ? — Enjeux et motivations »Problèmes résolus
Section intitulée « Problèmes résolus »| Problème | Solution Odoo |
|---|---|
| Données éparpillées | Base unifiée : projets, temps, contacts |
| Pas de traçabilité GitHub ↔ tâches | Sync bidirectionnelle via project_github_sync |
| Estimation au doigt mouillé | Champs x_estimated_hours / x_complexity + actual_hours réel via timesheets |
| Triage manuel des issues | Double-triage AI (x_ai_project_triaged_at + x_ai_personal_triaged_at) |
| Effort Claude Code invisible | Télémétrie par session (project.task.claude.session) avec coûts, tokens, LOC, TLDR, catégorie |
| Attribution marketing floue | Tracking de sources via Website (CV, carte visite, LinkedIn) |
Pourquoi Odoo 18 Community (vs Enterprise) ?
Section intitulée « Pourquoi Odoo 18 Community (vs Enterprise) ? »- Coût — Enterprise est facturé par utilisateur/mois. Community est gratuit et auto-hébergé.
- Modules custom sans contrainte — Aucune restriction sur l’installation de
project_github_syncouwebsite_experimentscôté Community. - Suffisance fonctionnelle — Les modules natifs Project, Timesheets, Website, CRM couvrent les besoins actuels.
- Migration possible — Vers Enterprise plus tard si besoin de modules avancés (eCommerce, Manufacturing).
3. Comment ? — Mise en œuvre technique
Section intitulée « 3. Comment ? — Mise en œuvre technique »Architecture réseau
Section intitulée « Architecture réseau »Configuration Docker Compose (extrait)
Section intitulée « Configuration Docker Compose (extrait) »services: odoo: image: odoo:18 volumes: - odoo-data:/var/lib/odoo - odoo-config:/etc/odoo - ./addons:/mnt/extra-addons environment: - HOST=odoo-postgres - USER=odoo - PASSWORD=${ODOO_DB_PASSWORD} healthcheck: test: ["CMD", "curl", "-f", "http://localhost:8069/web/health"] interval: 30s timeout: 10s retries: 3 networks: [odoo-internal, webproxy]
odoo-postgres: image: postgres:15 volumes: [odoo-db:/var/lib/postgresql/data] environment: - POSTGRES_USER=odoo - POSTGRES_PASSWORD=${ODOO_DB_PASSWORD} - POSTGRES_DB=guig_db networks: [odoo-internal]Module project_github_sync (v18.0.5.6.0)
Section intitulée « Module project_github_sync (v18.0.5.6.0) »Le module ajoute un grand nombre de champs à project.task (ainsi qu’un modèle dédié à l’historique des sessions Claude Code). Les champs sont regroupés en quatre familles.
Champs GitHub (8)
Section intitulée « Champs GitHub (8) »| Champ | Type | Usage |
|---|---|---|
x_github_sync_enabled | Boolean (sur project.project) | Active la sync sur le projet |
x_github_repo | Char | owner/repo source |
x_github_issue_id | Integer | Numéro de l’issue / PR |
x_github_url | Char | URL canonique vers GitHub |
x_github_commit_ids | One2many → project.task.commit | Commits liés (sha, message, author, url) |
x_github_commit_count | Integer (compute) | Nombre de commits liés |
x_github_milestone_id | Integer | Numéro du milestone GitHub |
x_github_parent_issue_id | Integer | Issue parente (sub-issues) |
Champs télémétrie Claude Code (13)
Section intitulée « Champs télémétrie Claude Code (13) »Alimentés par les hooks SessionEnd (voir Claude Code Telemetry).
| Champ | Type | Usage |
|---|---|---|
x_claude_time_total | Float (h) | Temps Claude Code agrégé |
x_claude_cost_total | Float ($) | Coût agrégé |
x_claude_token_total | Integer | Total tokens (in + out + cache) |
x_claude_tokens_input / _output / _cache | Integer × 3 | Détail par catégorie |
x_claude_sessions | Integer | Nombre de sessions |
x_claude_lines_added / _removed | Integer × 2 | LOC agrégées |
x_claude_last_session | Datetime | Dernière session enregistrée |
x_claude_cost_by_model | Text (JSON) | Répartition par modèle (Sonnet/Opus/Haiku) |
x_claude_session_ids | One2many → project.task.claude.session | Historique session par session |
x_claude_category | Selection | Catégorie auto pour les tâches génériques (sans issue) |
Chaque ligne project.task.claude.session capture le détail d’une session : ID, timestamps, tokens, coût, LOC, TLDR (résumé court généré par le hook) et catégorie. Cela permet de remonter de l’agrégat à la session source.
Champs estimation effort (#188)
Section intitulée « Champs estimation effort (#188) »| Champ | Type | Usage |
|---|---|---|
x_estimated_hours | Float | Estimation a priori |
x_complexity | Selection | Complexité (low / medium / high) |
La vérité terrain vient des timesheets : actual_hours = SUM(account.analytic.line.unit_amount) WHERE task_id = X. L’attribut x_claude_time_total n’est pas substituable — il mesure le temps machine Claude, pas l’effort humain. Voir le workflow Effort Estimator V1 pour la logique d’estimation cohort-based.
-- Échantillons appariés (estimé + réel) pour ré-calibrerSELECT t.id, t.name, t.x_estimated_hours, COALESCE(SUM(a.unit_amount), 0) AS actual_hours, t.x_claude_time_total, t.x_claude_sessionsFROM project_task tLEFT JOIN account_analytic_line a ON a.task_id = t.idWHERE t.x_estimated_hours IS NOT NULLGROUP BY t.id, t.name, t.x_estimated_hours, t.x_claude_time_total, t.x_claude_sessionsHAVING COALESCE(SUM(a.unit_amount), 0) > 0;Champs double-triage AI (#296)
Section intitulée « Champs double-triage AI (#296) »| Champ | Type | Usage |
|---|---|---|
x_ai_project_triaged_at | Datetime | Cache du dernier triage côté projet (stage) |
x_ai_personal_triaged_at | Datetime | Cache du dernier triage côté horizon perso (Aujourd’hui / Cette semaine / …) |
Le workflow N8N Daily GitHub Issue Triage propose des affectations stage + horizon via codex-yolo, puis stocke le timestamp pour ne pas re-triager pendant 7 jours (TTL configurable). L’utilisateur valide via Telegram (/triage), ce qui POST vers une API interne qui met à jour Odoo.
Module website_experiments
Section intitulée « Module website_experiments »Ajoute trois snippets drag-and-drop au Website Builder :
- Flip Display : afficheur split-flap animé (style aéroport).
- Glass Splat Desktop : 3 panneaux side-by-side avec rendu 3D verre fragmenté.
- Glass Splat Mobile : carrousel mobile équivalent.
Côté assets : CSS + IIFE JavaScript chargés via web.assets_frontend.
Filestore et ir_attachment
Section intitulée « Filestore et ir_attachment »Le filestore est dans le volume odoo-data, sous /var/lib/odoo/filestore/odoo/ (sous-dossier nommé odoo historiquement, même si la DB s’appelle maintenant guig_db). Il stocke tous les binaires référencés par ir_attachment.store_fname.
Sauvegarde
Section intitulée « Sauvegarde »Les backups sont gérés par scripts/backup-databases.sh (cron quotidien 03:00) qui produit :
pg_dump -U odoo guig_db→ archive SQLtar czf - -C /var/lib/odoo filestore→ archive du filestore- Rotation locale (7 j) + push GDrive (30 j) via rclone.
# Backup manueldocker exec odoo-postgres pg_dump -U odoo guig_db > odoo_backup.sql
# Restaurationdocker exec -i odoo-postgres psql -U odoo guig_db < odoo_backup.sql
# Backup filestore manueldocker exec odoo tar czf - -C /var/lib/odoo filestore > odoo-filestore.tar.gzIntégration N8N via XML-RPC
Section intitulée « Intégration N8N via XML-RPC »// Création d'une tâche depuis github-project-sync{ "url": "http://odoo:8069/xmlrpc/2/object", "method": "POST", "body": { "service": "object", "method": "execute_kw", "args": [ "guig_db", // database (PAS "odoo") 2, // uid après authentification "{{ $env.ODOO_PASSWORD }}", "project.task", "create", [{ "name": "Issue #123 — Fix bug", "project_id": 1, "x_github_issue_id": 123, "x_github_url": "https://github.com/owner/repo/issues/123" }] ] }}Gestion des modules
Section intitulée « Gestion des modules »# Installer un nouveau modulecp -r mon_module odoo-stack/addons/docker restart odoo# UI : Apps → Update Apps List → Installer
# Mettre à jour un module existant en placedocker exec odoo odoo -u project_github_sync -d guig_db --stop-after-initCommandes de dépannage
Section intitulée « Commandes de dépannage »# Health checkcurl http://localhost:8069/web/health
# Logs Odoodocker logs odoo --tail 100
# Connexion PostgreSQLdocker exec odoo-postgres pg_isready -U odoodocker exec odoo-postgres psql -U odoo -d guig_db -c "SELECT count(*) FROM project_task;"
# Shell Odoo pour debugdocker exec -it odoo odoo shell -d guig_db
# Regarder les sessions Claude récentesdocker exec odoo-postgres psql -U odoo -d guig_db \ -c "SELECT id, name, tldr, category FROM project_task_claude_session ORDER BY id DESC LIMIT 10;"4. Et si ? — Perspectives et limites
Section intitulée « 4. Et si ? — Perspectives et limites »Limites actuelles
Section intitulée « Limites actuelles »| Limite | Impact | Mitigation |
|---|---|---|
| Community sans support éditeur | Pas de hotline Odoo | Documentation + communauté |
| PostgreSQL single-instance | Pas de HA native | Backups quotidiens + monitoring |
| Modules custom à maintenir | Compat future Odoo 19+ | Migrations versionnées dans migrations/ |
| Single-user effectif | Toute la télémétrie est attribuée à un seul employé | Mapping multi-user prévu côté timetrackr_user_mapping si besoin |
Scénarios d’évolution
Section intitulée « Scénarios d’évolution »Si le pipeline d’estimation devient critique :
- Calibrer le modèle V1 → V2 sur les paired samples (
x_estimated_hoursvsactual_hours). - Étendre la télémétrie aux tâches sans issue (déjà adressé via
x_claude_category).
Si le triage AI devient bruyant :
- Réduire la TTL du cache (actuellement 7 j) pour re-triager plus souvent.
- Filtrer côté workflow par projet ou label.
Si besoin de facturation :
- Activer le module Invoicing.
- Connecter les
account.analytic.lineaux factures via tâches/projets.
Si migration vers Enterprise :
- Audit des champs custom et des migrations existantes.
- Vérifier la compatibilité de
project_github_sync(LGPL-3, devrait passer). - Budget : tarification par utilisateur/mois.
Pages liées
Section intitulée « Pages liées »Infrastructure
Section intitulée « Infrastructure »- Architecture VPS — Vue d’ensemble
- Pourquoi Odoo — Comparaison ERP et choix
- TimeTrackr Stack — Source des
account.analytic.line
Workflows
Section intitulée « Workflows »- GitHub-Odoo Sync — Synchronisation issues / PRs / commits
- Claude Code Telemetry — Hooks SessionStart / SessionEnd
- Cal.com → Odoo RDV — Intégration calendrier
Référence
Section intitulée « Référence »- Glossaire — ERP, XML-RPC, ir_attachment