Une seule dépendance dure : une chaîne de connexion PostgreSQL
Comment on a conçu une plateforme ambitieuse pour qu'elle démarre sur un serveur modeste, sans Docker, sans Redis, sans file d'attente.
Sur le papier, WeMovA est une plateforme à quatre étages : réseau, place de marché, paiement, intelligence. Le genre de feuille de route qui appelle une architecture « sérieuse » : Kubernetes, Redis, Kafka, un bucket objet, trois bases.
On a pris la décision inverse. La plateforme n'a qu'une seule dépendance obligatoire : une chaîne de connexion PostgreSQL. Tout le reste est optionnel.
D'où vient la contrainte
Pas d'un goût pour la simplicité. D'un constat sur le terrain.
Le premier déploiement d'un produit africain ne se fait pas sur un cluster managé à 400 dollars par mois. Il se fait sur un VPS à 10 dollars, parfois sur une machine dans un bureau, avec une connexion qui tombe. Si l'architecture exige six services pour démarrer, elle ne démarre pas — ou elle démarre dans un état que personne ne sait dépanner à 22 h un dimanche.
Une contrainte forte posée dès le premier jour vaut mieux qu'une optimisation faite plus tard. Plus tard, il y a du code partout qui suppose Redis.
Ce que PostgreSQL fait à la place des autres
Presque tout, en réalité, tant que le trafic est celui d'un produit qui démarre.
Le cache : une table avec une clé, une valeur JSON et une date d'expiration. Moins rapide que Redis, largement assez pour des profils et des listes.
La file d'attente : une table de tâches et SELECT … FOR UPDATE SKIP LOCKED. Plusieurs workers peuvent consommer sans se marcher dessus, de façon transactionnelle. C'est plus fiable que la plupart des files légères, parce que la tâche et la donnée qu'elle modifie vivent dans la même transaction.
with next_job as (
select id from jobs
where status = 'pending' and run_at <= now()
order by run_at
for update skip locked
limit 1
)
update jobs set status = 'running', started_at = now()
from next_job where jobs.id = next_job.id
returning jobs.*;La recherche : le plein-texte natif d'abord. La similarité vectorielle avec pgvector ensuite, quand elle est installée — et seulement alors. Le code vérifie la présence de l'extension au démarrage et bascule sur le plein-texte sinon.
Les fichiers : sur disque au départ, derrière une interface de stockage. Le bucket objet arrive quand il y a des fichiers à mettre dedans, pas avant.
Optionnel, pas absent
La nuance compte. Redis, pgvector, un stockage objet : chacun est prévu, chacun a une interface, chacun a un adaptateur. Ce qui est interdit, c'est qu'un seul d'entre eux soit requis pour que la plateforme fonctionne.
Concrètement, la configuration a exactement une variable obligatoire. Chaque autre variable absente déclenche un repli documenté, et le journal de démarrage dit lequel.
[startup] database: connected (postgres 16)
[startup] cache: postgres table (REDIS_URL not set)
[startup] search: full-text (pgvector extension not found)
[startup] storage: local disk ./data (S3_BUCKET not set)Personne ne découvre en production qu'il manque une pièce. Le système dit ce qu'il fait, et il le fait quand même.
Ce qu'on perd, et quand on le récupère
On perd de la performance sur le cache et de la latence sur la recherche, à partir de quelques milliers d'utilisateurs actifs. C'est le bon moment pour ajouter Redis : on a alors des utilisateurs, donc des revenus, donc un budget d'infrastructure, et surtout des mesures réelles pour savoir quoi optimiser.
Ajouter une dépendance à ce stade est une décision d'exploitation, prise avec des chiffres. La retirer quand elle est partout dans le code est une réécriture.
La règle que j'en ai tirée
Chaque dépendance d'infrastructure doit répondre à une question : que se passe-t-il si elle n'est pas là ? Si la réponse est « ça ne démarre pas », il faut soit la rendre optionnelle, soit être certain qu'elle sera là partout où le produit tournera. Pour un produit qui vise un continent où l'infrastructure est inégale, la première option est la seule honnête.
À lire ensuite
Un système de paiement commence par un ledger, pas par une API
Pourquoi la comptabilité à double entrée n'est pas un détail d'implémentation quand on fait circuler l'argent des autres.
Isoler les données de plusieurs entreprises dans une seule base
Row Level Security dans PostgreSQL : le piège du rôle superutilisateur, et pourquoi le filtre applicatif ne suffit pas.
FastAPI en production : ce qui compte vraiment
Cinq réglages qu'on ne voit dans aucun tutoriel et qui font la différence entre une API qui tourne et une API qu'on peut exploiter.