Skip to content

Module — Développement local

Setup pour faire tourner better-search sur un poste dev. Le tooling Python utilise uv (installeur déterministe rapide).

Prérequis

  • Python 3.13 (managé par uv, pas besoin d'install système).
  • Docker + Docker Compose (pour Postgres + pgvector).
  • uv (curl -LsSf https://astral.sh/uv/install.sh | sh ou via brew/apt).
  • Accès aux credentials Infomaniak (pour ingestion réelle). En leur absence, le service plante au boot (assert os.getenv(var, '') != '' dans app.py).

Boot rapide

sh
# 1. Récupérer les secrets (Infomaniak PID + token)
echo "<pid>" > infomaniak_pid.txt        # ou via .env
echo "<token>" > infomaniak_token.txt

# 2. Créer un .env avec les vars que docker-compose.yml lit
cat > .env <<EOF
INFOMANIAK_PID=<pid>
INFOMANIAK_TOKEN=<token>
EOF

# 3. Build et démarrage
docker compose up --build

# 4. Test
curl http://localhost:8088/
# {"app-name": "better-search", "datetime": "...", ...}

curl 'http://localhost:8088/travels?size=3'

L'image build, Postgres démarre, le service applique les migrations yoyo, puis lance un reindex initial (puisque la DB est vide). Quelques dizaines de secondes pour avoir un index complet.

Stack Compose (docker-compose.yml)

  • Service postgres : pgvector/pgvector:pg17. User better_search / password better_search_pwd / DB better_search. Pas de volume persistant — toute la DB part au docker compose down.
  • Service better-search : build local, mount .:/app (live source code).
  • Ports : 8088 → 80 côté API, 5432 → 5432 côté Postgres.
  • Vars d'env :
    • SLOW_SEARCH_URL=https://horizon.buchard.ch/api/travels (par défaut, peut pointer ailleurs en .env).
    • WITH_DOCS=true — Swagger UI accessible sur http://localhost:8088/docs.
    • DEFAULT_RRF_VECTOR_WEIGHT=0.4, DEFAULT_SEMANTIC_FLOOR=0.5, DEFAULT_TSVECTOR_FLOOR=0.0 — réglages dev plus permissifs.
    • REINDEX_FREQUENCY=900 — 15 min.

Workflow d'itération

Modifier du Python

Le volume - .:/app partage le code, mais FastAPI ne reload pas à chaud (lancé via fastapi run, pas fastapi dev). Deux options :

  1. Redémarrer le conteneur : docker compose restart better-search.
  2. Lancer FastAPI en local plutôt que conteneur, contre la DB Compose :
    sh
    uv sync                           # installe les deps
    export DATABASE_URL=postgresql://better_search:better_search_pwd@localhost:5432/better_search
    export SLOW_SEARCH_URL=https://horizon.buchard.ch/api/travels
    export INFOMANIAK_PID=<...>
    export INFOMANIAK_TOKEN=<...>
    uv run fastapi dev app.py --port 8088
    Avec dev, FastAPI watch les fichiers et reload.

Modifier une migration

sh
# Appliquer la nouvelle migration sur la DB dev
uv run yoyo apply --database "postgresql://better_search:better_search_pwd@localhost:5432/better_search" ./migrations --batch

# Vérifier le schéma
docker compose exec postgres psql -U better_search -d better_search -c '\d travels'

Si la migration touche les colonnes générées, faire un reindex pour rebuild les vecteurs / search_vector / etc. :

sh
curl http://localhost:8088/reindex

Repartir d'une DB propre

sh
docker compose down -v        # supprime les containers + le volume
docker compose up --build     # repart de zéro (migrations + reindex)

(Pas de volume persistant en dev, donc down suffit en fait — -v est par habitude.)

Tests

DB de test sur un autre port (5433) pour cohabiter avec le dev.

sh
# 1. Lancer la DB test
docker compose -f docker-compose-test.yml up -d

# 2. Appliquer les migrations
uv run yoyo apply --database "postgresql://better_search:better_search_pwd@localhost:5433/better_search_test" ./migrations --batch

# 3. Lancer les tests
uv sync --group test
uv run pytest tests/ -v

Ou en une commande :

sh
docker compose -f docker-compose-test.yml up -d && \
  uv sync --group test && \
  uv run yoyo apply --database "postgresql://better_search:better_search_pwd@localhost:5433/better_search_test" ./migrations --batch && \
  uv run pytest tests/ -v --cov=src --cov-report=term-missing

Détail des tests : modules/testing.md.

Accès psql

sh
# Dev
docker compose exec postgres psql -U better_search -d better_search

# Test
docker compose -f docker-compose-test.yml exec postgres-test psql -U better_search -d better_search_test

Quelques commandes utiles :

sql
\dt                                       -- liste des tables
\d travels                                -- schéma de travels (colonnes générées visibles)
\dv                                       -- liste des vues
SELECT COUNT(*) FROM travels;
SELECT id, name, destination FROM travels_view LIMIT 5;
SELECT id, ts_rank_cd(search_vector, websearch_to_tsquery('french', 'ski')) AS s
  FROM travels_view ORDER BY s DESC LIMIT 5;

Reset des fixtures de test

Les fixtures test_embeddings.json et test_query_embeddings.json contiennent des embeddings réels capturés à un moment donné. Pour les regénérer (si on change de modèle d'embedding) :

sh
# Script à écrire — pas fourni dans le repo. Schéma :
#   pour chaque travel dans test_db.json:
#     emb = infomaniak.get_embedding_text(travel) → vecteur
#     write to test_embeddings.json
#   pour chaque query string testée:
#     emb = infomaniak.get_embedding(query) → vecteur
#     write to test_query_embeddings.json

À ce jour, les fixtures n'ont pas été regénérées depuis le baseline. Si on change de modèle ou de service d'embedding, ça devient un blocker.

Pièges fréquents

  • assert au boot : app.py plante si SLOW_SEARCH_URL, EMBEDDING_URL, INFOMANIAK_PID, INFOMANIAK_TOKEN ne sont pas définis. Pas un message clair — c'est juste un AssertionError. Le .env doit fournir ces 4 vars.
  • db = BuchardDatabase() au top-level : importer src.db déclenche un reindex si la DB est stale. Les tests utilisent auto_reindex=False.
  • Port 5432 occupé : si vous avez un Postgres système qui tourne déjà, conflits. Soit sudo service postgresql stop, soit changer le port mapping dans docker-compose.yml.
  • Image stale : docker compose up --build rebuild seulement si Dockerfile ou pyproject.toml change. Pour forcer un rebuild complet : docker compose build --no-cache better-search.
  • uv.lock désynchro : après un uv add, commit le lock. Sinon CI plante (--frozen).
  • Live edit en conteneur : grâce au mount -.:/app, les fichiers édités sont visibles dans le conteneur. Mais fastapi run ne reload pas — restart requis. Mieux : fastapi dev en local (cf. plus haut).

Contributors

No contributors

Changelog

No recent changes