02-ce-que-je-construis/specs/telaria-search.md

Telaria Search

Telaria Search est le moteur de recherche interne de Codexia. Il unifie la recherche BDD et fichiers, tout en restant agnostique du moteur pour démontrer une architecture industrielle sans dépendance à un bundle tiers. Il s'appuie sur des composants open source éprouvés et s'aligne sur les principes de longévité et de simplicité maîtrisée. Sources : Philosophie, Ingénierie, Architecture.

Objectifs

  • Démontrer une implémentation industrielle malgré une volumétrie réduite (vitrine de savoir-faire). Source : Philosophie.
  • Garder une architecture lisible, maintenable, extensible (KISS et Clean Code). Source : Ingénierie.
  • Prioriser l'open source et les standards. Source : Philosophie.

Périmètre fonctionnel

  • Recherche full-text sur un sous-ensemble de tables et de champs (whitelist).
  • Recherche full-text sur des fichiers textuels ou bureautiques via extraction dédiée.
  • Filtrage par type de contenu, langue, statut, domaine d'expertise, date.
  • Respect des règles d'accès (public / privé / rôles).

Architecture logique (moteur agnostique)

┌─────────────────────────────┐
│        Couche HTTP          │
│  Controller / API Search    │
└──────────────┬──────────────┘
               │
               ▼
┌─────────────────────────────┐
│     Service de recherche    │
│   (SearchService interne)   │
└──────────────┬──────────────┘
               │
               ▼
┌─────────────────────────────┐
│     Port moteur (interface) │
│  SearchEnginePort (PHP)     │
└──────────────┬──────────────┘
               │
     ┌─────────┴─────────┐
     ▼                   ▼
┌───────────────┐   ┌───────────────┐
│ OpenSearch    │   │ Autre moteur  │
│ Adapter       │   │ Adapter       │
└───────────────┘   └───────────────┘

Notion de port (ports & adapters)

Un port est un contrat d'interface défini par l'application, indépendant de toute technologie externe. Les adaptateurs implémentent ce contrat pour un moteur concret. Cette séparation rend le coeur applicatif stable, testable et remplaçable sans réécriture des cas d'usage. Source : Hexagonal architecture.

Ce que cela implique :

  • Le coeur applicatif dépend d'une interface, jamais d'un client spécifique.
  • Le changement de moteur se limite à remplacer l'adaptateur.
  • Les tests peuvent utiliser un adaptateur in-memory sans dépendance réseau.

Composants internes

  • SearchService : expose une API unique pour la recherche.
  • SearchIndexer : normalise les données à indexer (BDD et fichiers).
  • SearchEnginePort : interface PHP commune (indexer, supprimer, rechercher).
  • OpenSearchAdapter : implémentation par défaut via le client PHP officiel. Source : Client PHP OpenSearch.
  • IndexMappingFactory : définit le schéma de l'index (types, analyzers).
  • SearchQueue : orchestration asynchrone via Symfony Messenger. Source : Symfony Messenger.

Mise en place du port (Symfony)

Le port est une interface PHP placée dans le coeur applicatif. L'adaptateur est un service d'infrastructure qui implémente l'interface. L'alias du conteneur Symfony relie l'interface à l'adaptateur choisi. Source : Autowiring Symfony.

Installation côté Symfony :

  • Créer l'interface SearchEnginePort dans src/Search/Port/.
  • Implémenter l'adaptateur dans src/Search/Infrastructure/.
  • Déclarer un alias d'interface dans services.yaml (autowiring).
  • Injecter le port dans les services applicatifs (SearchService, SearchIndexer). Source : Autowiring Symfony.

Exemple minimal :

// src/Search/Port/SearchEnginePort.php
namespace App\Search\Port;

interface SearchEnginePort
{
    public function index(array $document): void;
    public function delete(string $type, string $id): void;
    public function search(string $query, array $filters = []): array;
}
# config/services.yaml
services:
    App\Search\Port\SearchEnginePort:
        alias: App\Search\Infrastructure\OpenSearchAdapter

Choix moteur par défaut : OpenSearch

Configuration OpenSearch (Symfony)

Installation du client :

composer require opensearch-project/opensearch-php

Source : Client PHP OpenSearch.

Variables d'environnement recommandées :

OPENSEARCH_HOST=https://localhost:9200
OPENSEARCH_USER=admin
OPENSEARCH_PASSWORD=admin
OPENSEARCH_SSL_VERIFY=true

Exemple d'adaptateur (extrait) :

use OpenSearch\ClientBuilder;

$client = ClientBuilder::create()
    ->setHosts([$_ENV['OPENSEARCH_HOST']])
    ->setBasicAuthentication($_ENV['OPENSEARCH_USER'], $_ENV['OPENSEARCH_PASSWORD'])
    ->setSSLVerification((bool) $_ENV['OPENSEARCH_SSL_VERIFY'])
    ->build();

Source : Client PHP OpenSearch.

Sécurisation réseau (TLS, CA, reverse proxy)

Objectif : chiffrer les communications, valider la CA et éviter une exposition directe.

TLS côté OpenSearch (REST + transport) :

# opensearch.yml (extrait)
plugins.security.ssl.http.enabled: true
plugins.security.ssl.http.pemcert_filepath: certs/opensearch-http.pem
plugins.security.ssl.http.pemkey_filepath: certs/opensearch-http-key.pem
plugins.security.ssl.http.pemtrustedcas_filepath: certs/root-ca.pem

plugins.security.ssl.transport.pemcert_filepath: certs/opensearch-transport.pem
plugins.security.ssl.transport.pemkey_filepath: certs/opensearch-transport-key.pem
plugins.security.ssl.transport.pemtrustedcas_filepath: certs/root-ca.pem

Source : OpenSearch TLS.

Reverse proxy Apache (optionnel) :

# Apache (reverse proxy)
ProxyPass "/opensearch" "https://127.0.0.1:9200"
ProxyPassReverse "/opensearch" "https://127.0.0.1:9200"

Le reverse proxy s'active avec ProxyPass / ProxyPassReverse et ne nécessite pas ProxyRequests. Source : Apache mod_proxy.

Extraction de contenu fichiers (Tika)

  • Apache Tika détecte et extrait texte et métadonnées depuis un grand nombre de formats. Source : Apache Tika.
  • Le mode serveur est supporté via l'option -s de tika-app, pratique pour un service dédié. Source : Getting Started Tika.

Installation Apache Tika (Ubuntu)

  1. Choisir une version explicite et récupérer le jar exécutable depuis la page officielle. Source : Téléchargement Tika.
  2. Installer un runtime Java (exemple : OpenJDK) et placer le jar dans un répertoire dédié.
  3. Démarrer Tika en mode serveur :
java -jar /opt/tika/tika-app-<version>.jar -s

Source : Getting Started Tika.

Exemple de service systemd (optionnel) :

[Unit]
Description=Apache Tika Server
After=network.target

[Service]
User=tika
Group=tika
ExecStart=/usr/bin/java -jar /opt/tika/tika-server-<version>.jar --host=127.0.0.1 --port=9998
Restart=on-failure

[Install]
WantedBy=multi-user.target

Par défaut, Tika Server écoute sur localhost:9998 et le port peut être modifié via --port. Source : TikaServer.

Modèle de document indexé (schéma minimal)

Champs communs (tous les types) :

  • type : document, resource, file, etc.
  • source_id : identifiant métier.
  • title : titre court.
  • content : texte principal indexé.
  • language : fr ou en.
  • tags : liste de tags (si applicable).
  • visibility : public, privé, rôle.
  • updated_at : date de mise à jour.

Flux d'indexation

1. Indexation BDD

  1. Doctrine émet un événement sur création ou mise à jour.
  2. SearchIndexer construit le document indexable en appliquant la whitelist de champs.
  3. Le message est envoyé à Messenger.
  4. Le handler appelle SearchEnginePort pour indexer.

2. Indexation fichiers

  1. Upload ou ingestion de fichier.
  2. Envoi du fichier à Tika (serveur dédié) pour extraction du texte.
  3. SearchIndexer normalise le document et ajoute les métadonnées.
  4. Indexation via SearchEnginePort.

Recherche (requêtes)

  • Recherche multi-champs (titre + contenu) avec pondération.
  • Filtres métiers appliqués côté moteur (type, langue, statut).
  • Pagination simple et stable.

Sécurité et conformité

  • Filtrage des résultats en fonction de la visibilité métier.
  • Aucune exposition directe de l'endpoint OpenSearch vers le public.
  • Journalisation des erreurs d'indexation et des erreurs Tika. Sources : Ingénierie, Architecture.

Accessibilité (RGAA AA)

  • Formulaire de recherche avec libellé explicite et aide à la saisie.
  • Résultats dans une liste structurée, focus visible et navigation clavier.
  • Mise en évidence des occurrences sans dépendre uniquement de la couleur. Sources : Accessibilité, Interface utilisateur.

Observabilité et performance

  • Logs structurés pour chaque opération d'indexation.
  • Indexation asynchrone pour ne pas bloquer le backoffice.
  • Possibilité de re-indexation complète via commande Symfony. Source : Symfony Messenger.

Évolutivité

  • Ajout d'un nouveau moteur via un adapter supplémentaire (Meilisearch, Elasticsearch, Solr).
  • Les appels applicatifs restent inchangés grâce au SearchEnginePort.

Liens internes


Implémentation

Aspect Localisation
Statut Conceptuel — mis en pause au profit de l'initiative IA (cf. ia-vitrine.md)
Bundle principal À documenter — module src/Search/ dans telaria-app (prospectif)
Port moteur src/Search/Port/SearchEnginePort.php (interface)
Adaptateur par défaut src/Search/Infrastructure/OpenSearchAdapter.php
Services SearchService, SearchIndexer dans telaria-app
Async Symfony Messenger (SearchQueue)
Extraction fichiers Apache Tika (serveur dédié, localhost:9998)
Config Variables OPENSEARCH_HOST, OPENSEARCH_USER, OPENSEARCH_PASSWORD, OPENSEARCH_SSL_VERIFY

Historique des décisions

Version Date Décision
1.0 2026-06-14 Version initiale — première formalisation du versioning des specs.
2026-05-28 telaria-search mis en pause au profit de l'initiative IA (SQLite + sqlite-vec retenu pour le retrieval RAG). Spec conservée comme référence pour une future activation.

Assistant documentaire

Posez une question sur la documentation. Les réponses citent leurs sources — un clic ouvre le document à gauche.

Loading…
Loading the web debug toolbar…
Attempt #