gigafibre-fsm/docs/karrio-shipping.md
louispaulb 3a90dafb9f docs: déploiement Karrio (expédition multi-transporteurs self-hosted) + sources
Architecture, accès, Dockerfile.carriers + override compose (sanitisés), transporteurs
(Canada Post/Purolator/Canpar/Nationex/Dicom/BoxKnight + agrégateurs eShipper/Freightcom),
pièges (collision hostname, admin, binaire venv), plan d'intégration hub #54. Sources incluses.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-04 10:25:36 -04:00

7.1 KiB
Raw Permalink Blame History

Karrio — plateforme d'expédition multi-transporteurs (self-hosted)

Karrio est l'EasyPost/Shippo open-source (LGPL), auto-hébergé sur le serveur de prod. Il fournit, sous une API unifiée, le calcul de tarif d'expédition + étiquettes + suivi à travers de nombreux transporteurs (BYOCA : on branche nos propres comptes, 0 frais par étiquette).

Objectif : calculer les frais de livraison au checkout de la boutique matériel (/store) et gérer l'expédition des commandes (#54). Déployé le 2026-06-04.

⚠️ Ce document ne contient aucun secret. Les identifiants vivent sur le serveur (/opt/karrio/.env, /opt/karrio/ADMIN_CREDS.txt).


Accès

Quoi URL
Dashboard (GUI gestion transporteurs) https://karrio.gigafibre.ca — connexion admin@targo.ca (mdp : /opt/karrio/ADMIN_CREDS.txt)
API publique https://api.karrio.gigafibre.ca
API interne (depuis le hub) http://karrio.api:5002 (réseau Docker erpnext_erpnext)
Auth API POST /api/token {email,password} → JWT access

DNS Cloudflare : karrio + api.karrio.gigafibre.ca → 96.125.196.67, DNS-only (proxied=false, comme msg/erp, pour le challenge Let's Encrypt). TLS via Traefik (resolver letsencrypt).


Architecture

  • Emplacement : /opt/karrio/ (compose) ; source clonée dans /opt/karrio-src/ (Git).
  • Conteneurs : karrio.api (5002) · karrio.worker · karrio.dashboard (3002) · karrio.db (postgres:16 dédié) · karrio.redis · karrio.mail (maildev).
  • Réseaux Docker : karrio_default (interne) + erpnext_erpnext (pour que le hub joigne l'API)
    • proxy (Traefik). L'attache aux réseaux externes est dans docker-compose.override.yml (persistante).
  • Images : karrio/server + karrio/dashboard 2026.1.31. L'api/worker utilisent une image custom karrio-server-targo:2026.1.31 (transporteurs canadiens supplémentaires, voir plus bas).

Dockerfile.carriers (transporteurs canadiens opt-in)

FROM karrio.docker.scarf.sh/karrio/server:2026.1.31
# Transporteurs non bundlés dans l'image OSS (paquets PyPI gratuits)
RUN /karrio/venv/bin/pip install --no-cache-dir "karrio==2026.1.31" \
      karrio_canpar karrio_nationex karrio_dicom karrio_boxknight

Build : docker build -t karrio-server-targo:2026.1.31 -f Dockerfile.carriers .

docker-compose.override.yml (réseaux + image custom + labels Traefik)

networks:
  erpnext_erpnext: { external: true }
  proxy: { external: true }
services:
  api:
    image: karrio-server-targo:2026.1.31
    networks: [default, erpnext_erpnext, proxy]
    labels:
      - traefik.enable=true
      - traefik.docker.network=proxy
      - traefik.http.routers.karrio-api.rule=Host(`api.karrio.gigafibre.ca`)
      - traefik.http.routers.karrio-api.entrypoints=websecure
      - traefik.http.routers.karrio-api.tls.certresolver=letsencrypt
      - traefik.http.services.karrio-api.loadbalancer.server.port=5002
  worker:
    image: karrio-server-targo:2026.1.31
  dashboard:
    networks: [default, proxy]
    labels:
      - traefik.enable=true
      - traefik.docker.network=proxy
      - traefik.http.routers.karrio-dash.rule=Host(`karrio.gigafibre.ca`)
      - traefik.http.routers.karrio-dash.entrypoints=websecure
      - traefik.http.routers.karrio-dash.tls.certresolver=letsencrypt
      - traefik.http.services.karrio-dash.loadbalancer.server.port=3002

Variables .env clés (valeurs réelles sur le serveur)

KARRIO_TAG=2026.1.31
DATABASE_HOST=karrio.db        # nom de conteneur, PAS "db" (collision ERPNext)
REDIS_HOST=karrio.redis        # idem
USE_HTTPS=True
KARRIO_PUBLIC_URL=https://api.karrio.gigafibre.ca
DASHBOARD_URL=https://karrio.gigafibre.ca
ALLOW_SIGNUP=False
ADMIN_EMAIL=admin@targo.ca
# SECRET_KEY / JWT_SECRET / OIDC_RSA_PRIVATE_KEY / ADMIN_PASSWORD / DATABASE_PASSWORD : générés

Transporteurs disponibles

  • Bundlés (image OSS) : Canada Post, Purolator, UPS, FedEx, DHL (×4), GLS, USPS, DPD, Chronopost, La Poste, Sendle, Australia Post, eShipper, Freightcom, generic… (~29).
  • Ajoutés (image custom) : 🇨🇦 Canpar, Nationex (QC), Dicom / GLS Canada, BoxKnight (last-mile Montréal).
  • Agrégateurs canadiens (1 compte → multi-transporteurs à tarifs négociés, Canpar inclus) : eShipper, Freightcom (déjà bundlés).
  • Dispo sur PyPI si besoin (international) : karrio_tge, karrio_geodis, karrio_asendia, karrio_aramex. Non publiés : shiptime, loomis, intelcom, ics_courier.

Karrio OSS ne bundle qu'un sous-ensemble ; les autres transporteurs sont des paquets PyPI karrio_<nom> gratuits (pas une limitation de licence — du packaging). On les cuit dans l'image custom.


Pièges rencontrés (résolus)

  1. Collision de hostname : api étant sur le réseau partagé erpnext_erpnext, db/redis résolvaient vers le Postgres/Redis d'ERPNext (« password auth failed for user karrio »). → .env : DATABASE_HOST=karrio.db, REDIS_HOST=karrio.redis (noms de conteneurs non ambigus).
  2. Attache réseau : docker network connect est perdu au recreate → réseaux dans l'override.yml.
  3. Admin non auto-semé : créer manuellement — binaire = /karrio/venv/bin/karrio (absent du PATH en bash -lc → utiliser docker exec ... sh -c).
    docker exec -e KPW=<pw> karrio.api sh -c "cd /karrio/app && karrio shell < /tmp/mkadmin.py"
    # mkadmin.py : get_user_model().objects.create_superuser('admin@targo.ca', os.environ['KPW'])
    
  4. Réinit DB si besoin : docker compose down -v (sinon vieux creds persistent dans le volume).

Intégration prévue (hub → #54)

services/targo-hub/lib/shipping.js exposera quoteRates({origin, dest, parcel}) :

  1. token JWT (POST /api/token) → cache,
  2. appel API Karrio (rates) avec origine (entrepôt) + destination (client) + colis (poids = Item.weight_per_unit ERPNext),
  3. options de tarif → ligne « Frais de livraison » au checkout boutique,
  4. /store/checkout → Sales Invoice ERPNext (update_stock) + Stripe via lib/payments.js.

Sources

Mémoire interne liée : project_karrio_shipping.md.