Aller au contenu

Odoo 18 sur Docker

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 natifs activés :

ModuleUsage
ProjectProjets et tâches
Timesheetsaccount.analytic.line — alimenté par TimeTrackr
WebsitePage d’atterrissage et hub
CRMLeads et conversion (à étendre)

Modules custom maintenus dans odoo-stack/addons/ :

ModuleVersionUsage
project_github_syncv18.0.5.6.0Sync GitHub ↔ tâches + télémétrie Claude Code + double-triage AI + estimation
website_experimentsv18.0.1.1.0Snippets interactifs (Flip Display, Glass Splat) pour le Website Builder
powered_by_odoo_removetiersRetire le branding “Powered by Odoo” sur les pages publiques

CV / Carte visite · lien tracké

Website Odoo

Formulaire contact

Prise RDV Cal.com

CRM Odoo · Lead

Projet + Devis · estimé via x_estimated_hours / x_complexity

Issue GitHub · sync via project_github_sync

Claude Code · télémétrie x_claude_*

Pour comprendre pourquoi Odoo a été choisi parmi les alternatives, voir Pourquoi Odoo.


ProblèmeSolution Odoo
Données éparpilléesBase unifiée : projets, temps, contacts
Pas de traçabilité GitHub ↔ tâchesSync bidirectionnelle via project_github_sync
Estimation au doigt mouilléChamps x_estimated_hours / x_complexity + actual_hours réel via timesheets
Triage manuel des issuesDouble-triage AI (x_ai_project_triaged_at + x_ai_personal_triaged_at)
Effort Claude Code invisibleTélémétrie par session (project.task.claude.session) avec coûts, tokens, LOC, TLDR, catégorie
Attribution marketing floueTracking de sources via Website (CV, carte visite, LinkedIn)
  1. Coût — Enterprise est facturé par utilisateur/mois. Community est gratuit et auto-hébergé.
  2. Modules custom sans contrainte — Aucune restriction sur l’installation de project_github_sync ou website_experiments côté Community.
  3. Suffisance fonctionnelle — Les modules natifs Project, Timesheets, Website, CRM couvrent les besoins actuels.
  4. Migration possible — Vers Enterprise plus tard si besoin de modules avancés (eCommerce, Manufacturing).

port 8069

odoo-internal

Odoo 18 · :8069 · Web UI · XML-RPC · /mnt/extra-addons

odoo-postgres · :5432 · DB guig_db

Caddy · webproxy · odoo.guigpap.com:443

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]

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.

ChampTypeUsage
x_github_sync_enabledBoolean (sur project.project)Active la sync sur le projet
x_github_repoCharowner/repo source
x_github_issue_idIntegerNuméro de l’issue / PR
x_github_urlCharURL canonique vers GitHub
x_github_commit_idsOne2many → project.task.commitCommits liés (sha, message, author, url)
x_github_commit_countInteger (compute)Nombre de commits liés
x_github_milestone_idIntegerNuméro du milestone GitHub
x_github_parent_issue_idIntegerIssue parente (sub-issues)

Alimentés par les hooks SessionEnd (voir Claude Code Telemetry).

ChampTypeUsage
x_claude_time_totalFloat (h)Temps Claude Code agrégé
x_claude_cost_totalFloat ($)Coût agrégé
x_claude_token_totalIntegerTotal tokens (in + out + cache)
x_claude_tokens_input / _output / _cacheInteger × 3Détail par catégorie
x_claude_sessionsIntegerNombre de sessions
x_claude_lines_added / _removedInteger × 2LOC agrégées
x_claude_last_sessionDatetimeDernière session enregistrée
x_claude_cost_by_modelText (JSON)Répartition par modèle (Sonnet/Opus/Haiku)
x_claude_session_idsOne2many → project.task.claude.sessionHistorique session par session
x_claude_categorySelectionCaté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.

ChampTypeUsage
x_estimated_hoursFloatEstimation a priori
x_complexitySelectionComplexité (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é-calibrer
SELECT
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_sessions
FROM project_task t
LEFT JOIN account_analytic_line a ON a.task_id = t.id
WHERE t.x_estimated_hours IS NOT NULL
GROUP BY t.id, t.name, t.x_estimated_hours,
t.x_claude_time_total, t.x_claude_sessions
HAVING COALESCE(SUM(a.unit_amount), 0) > 0;
ChampTypeUsage
x_ai_project_triaged_atDatetimeCache du dernier triage côté projet (stage)
x_ai_personal_triaged_atDatetimeCache 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.

Daily Trigger / SessionStart hook

Fetch issues without triage cache or expiré

AI Issue Triage SW · codex-yolo

Update x_ai_*_triaged_at

triage-pending.json

Interactive triage via /triage

triage-interactive-api · POST update

Odoo · stage_id + x_personal_stage_id

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.

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.

Les backups sont gérés par scripts/backup-databases.sh (cron quotidien 03:00) qui produit :

  • pg_dump -U odoo guig_db → archive SQL
  • tar czf - -C /var/lib/odoo filestore → archive du filestore
  • Rotation locale (7 j) + push GDrive (30 j) via rclone.
Fenêtre de terminal
# Backup manuel
docker exec odoo-postgres pg_dump -U odoo guig_db > odoo_backup.sql
# Restauration
docker exec -i odoo-postgres psql -U odoo guig_db < odoo_backup.sql
# Backup filestore manuel
docker exec odoo tar czf - -C /var/lib/odoo filestore > odoo-filestore.tar.gz
// 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"
}]
]
}
}
Fenêtre de terminal
# Installer un nouveau module
cp -r mon_module odoo-stack/addons/
docker restart odoo
# UI : Apps → Update Apps List → Installer
# Mettre à jour un module existant en place
docker exec odoo odoo -u project_github_sync -d guig_db --stop-after-init
Fenêtre de terminal
# Health check
curl http://localhost:8069/web/health
# Logs Odoo
docker logs odoo --tail 100
# Connexion PostgreSQL
docker exec odoo-postgres pg_isready -U odoo
docker exec odoo-postgres psql -U odoo -d guig_db -c "SELECT count(*) FROM project_task;"
# Shell Odoo pour debug
docker exec -it odoo odoo shell -d guig_db
# Regarder les sessions Claude récentes
docker 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;"

LimiteImpactMitigation
Community sans support éditeurPas de hotline OdooDocumentation + communauté
PostgreSQL single-instancePas de HA nativeBackups quotidiens + monitoring
Modules custom à maintenirCompat future Odoo 19+Migrations versionnées dans migrations/
Single-user effectifToute la télémétrie est attribuée à un seul employéMapping multi-user prévu côté timetrackr_user_mapping si besoin

Si le pipeline d’estimation devient critique :

  • Calibrer le modèle V1 → V2 sur les paired samples (x_estimated_hours vs actual_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.line aux 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.