Site troll / Projet annexe

Mariage-Divorce

Se marier, divorcer et tester un couple en ligne, pour rire

JavaScriptPythonWebRTCSSEPodmancoturn

Mariage-Divorce (G·&·P dans le dépôt) est un projet troll, fait lors d’une soirée avec des potes. C’est une blague assumée, mais elle repose sur du vrai : presque tout vient de modules que j’avais déjà écrits, et le projet a surtout été un assemblage.

L'idée

Le site est une mairie imaginaire, « Undertainment », qui délivre des actes de mariage, de divorce et de testament. Chaque acte est un parchemin au format A4, avec en-tête de la République, numéro d’acte et cachet « Enregistré » une fois validé. Les champs se remplissent, deux signatures se tracent au doigt ou à la souris, et un compteur tient le registre des couples : combien de mariages, combien de divorces, et qui hérite de qui.

L'acte de mariage, rempli à plusieurs en direct (noms fictifs pour la capture)

Le reste du site suit la même veine. Une page « Thérapie de couple » affiche un post-it qui change à chaque visite et dit où est parti l’autre. Une page « Date » met deux personnes en vidéo, avec un décor au choix (restaurant, bar, cinéma). Une page « Recherche le Point G » fait passer un faux chargement et un faux captcha avant de montrer un simple miroir.

La page Thérapie de couple : un post-it différent à chaque visite

Des contrats partagés en direct

Il n’y a qu’un seul contrat de mariage et un seul contrat de divorce, communs à tous les visiteurs. Ce qu’on tape apparaît chez les autres, et une signature se voit se dessiner à l’écran des autres pendant qu’elle est tracée. Même la feuille se déplace : on la saisit et elle bouge chez tout le monde.

Le serveur garde l’état de chaque contrat et le diffuse en SSE. Les champs partent après une courte pause de frappe, les points d’un trait par petits paquets d’environ 50 ms, et l’image finale de la signature au lever du crayon. La feuille a une taille fixe (794 × 1123 px, un A4 à 96 dpi) mise à l’échelle selon l’écran, et les signatures sont tracées sur une toile de résolution fixe : tout le monde voit donc la même chose. Quand les deux ont signé, la validation fige le contrat, lui donne un numéro et l’inscrit au compteur.

Le testament fait exception. C’est un document individuel : le brouillon reste dans le navigateur de la personne, et seule la validation contacte le serveur.

Le compteur compare les noms avec tolérance : accents, casse, ponctuation, une faute de frappe, ordre des deux noms inversé. Sans ça, « Roméo » et « romeo » seraient deux couples différents.

Le compteur : mariages, divorces et héritiers par couple (couples fictifs pour la capture)

Ce qui tourne derrière

Le site tourne dans un pod Podman sur mon VPS, avec trois conteneurs : nginx pour les fichiers statiques et la redirection de l’API, une API en Python qui n’utilise que la bibliothèque standard, et coturn pour le relais vidéo. Les conteneurs sont déclarés en unités Quadlet pour systemd. Ils tournent sans privilèges (capacités retirées, système de fichiers en lecture seule, mémoire plafonnée).

La publication se fait par git push vers un dépôt du VPS. Un hook post-receive extrait main, copie le site, met à jour l’API, redémarre ce qui a changé et attend que /api/sante réponde avant de dire que c’est en ligne. Un script deployer.sh fait le commit et le push en une commande. Les données (événements du compteur, état des contrats) sont de simples fichiers JSON écrits de façon atomique.

J’ai gardé l’API en Python standard et le front sans framework ni build. Ça évite tout outillage, et le serveur tient dans un fichier.

La vidéo à deux

La page Date est un appel vidéo de navigateur à navigateur en WebRTC, avec PeerJS. Le premier arrivé sur un code prend l’identifiant du rendez-vous, le second s’y connecte avec le lien d’invitation. Le choix du décor est synchronisé entre les deux écrans.

Quand deux navigateurs ne peuvent pas se joindre directement (réseau d’entreprise, téléphone en 4G), l’appel passe par le relais coturn du pod. L’API délivre à chaque visiteur des identifiants temporaires, calculés avec un secret partagé avec coturn, et le relais refuse les adresses privées, limite le débit et le nombre de sessions. Sans l’API, le navigateur retombe sur un serveur STUN public.

Ce que ça m'a apporté

Ce n’est pas un projet jetable. Il reprend des bouts que j’avais déjà : des classes CSS, des scripts de déploiement, des morceaux de serveur. Il est monté presque uniquement par assemblage, et c’est ce qui m’intéresse.

En le faisant, j’ai construit une méthode et une base pour déployer un site web rapidement : une feuille de style modulaire déjà prête, un déploiement par git push et des scripts qui font le reste. Un prochain site peut partir de là, au lieu de repartir de zéro.

Limites

La barre de recherche du compteur est écrite mais désactivée tant que le site n’a pas assez de couples. Les contrats étant communs à tous, deux inconnus peuvent se retrouver à écrire sur la même feuille : c’est voulu, mais ça veut dire que le contenu n’est pas modéré. La mise en relation des appels passe par le serveur public de PeerJS, pas par un serveur à moi. Je n’ai pas testé le relais vidéo à grande échelle, et le dépôt ne contient pas de tests.

Liens

Joke site / Side project

Mariage-Divorce

Get married, get divorced and test a couple online, as a joke

JavaScriptPythonWebRTCSSEPodmancoturn

Mariage-Divorce (G·&·P in the repository) is a troll project, made during an evening with friends. The joke is deliberate, but it rests on real work: almost everything comes from modules I had already written, and the project was mostly an assembly.

The idea

The site is an imaginary town hall, “Undertainment”, that issues marriage, divorce and will certificates. Each certificate is an A4 parchment with the header of the French Republic, a certificate number and an “Enregistré” stamp once validated. The fields get filled in, two signatures are drawn with a finger or a mouse, and a counter keeps the register of couples: how many marriages, how many divorces, and who inherits from whom.

The marriage certificate, filled in by several people live (fictional names for the capture)

The rest of the site follows the same vein. A “Thérapie de couple” page shows a sticky note that changes at every visit and says where the other person went. A “Date” page puts two people on video, with a setting of their choice (restaurant, bar, cinema). A “Recherche le Point G” page runs a fake loading screen and a fake captcha before showing a plain mirror.

The Thérapie de couple page: a different sticky note at every visit

Contracts shared live

There is only one marriage contract and one divorce contract, shared by all visitors. What you type shows up for the others, and a signature can be seen being drawn on their screens while it is traced. Even the sheet moves: you grab it and it moves for everyone.

The server keeps the state of each contract and broadcasts it over SSE. Fields are sent after a short typing pause, the points of a stroke in small batches of about 50 ms, and the final signature image when the pen is lifted. The sheet has a fixed size (794 × 1123 px, an A4 at 96 dpi) scaled to the screen, and signatures are drawn on a fixed-resolution canvas, so everyone sees the same thing. Once both have signed, validation freezes the contract, gives it a number and adds it to the counter.

The will is the exception. It is an individual document: the draft stays in the person’s browser, and only validation contacts the server.

The counter compares names loosely: accents, case, punctuation, one typo, the two names swapped. Without that, “Roméo” and “romeo” would be two different couples.

The counter: marriages, divorces and heirs per couple (fictional couples for the capture)

What runs behind it

The site runs in a Podman pod on my VPS, with three containers: nginx for the static files and for proxying the API, an API in Python that uses only the standard library, and coturn for the video relay. The containers are declared as Quadlet units for systemd. They run without privileges (capabilities dropped, read-only filesystem, capped memory).

Publishing is done with a git push to a repository on the VPS. A post-receive hook checks out main, copies the site, updates the API, restarts what changed and waits for /api/sante to answer before saying it is online. A deployer.sh script does the commit and the push in one command. The data (counter events, contract state) is stored as plain JSON files, written atomically.

I kept the API in standard Python and the front end free of any framework or build step. That avoids any tooling, and the server fits in one file.

Video for two

The Date page is a browser-to-browser video call over WebRTC, with PeerJS. The first person to arrive on a code takes the meeting identifier, and the second connects to it from the invitation link. The choice of setting is synchronised between the two screens.

When two browsers cannot reach each other directly (company network, phone on 4G), the call goes through the pod’s coturn relay. The API hands each visitor temporary credentials, computed with a secret shared with coturn, and the relay refuses private addresses and limits bandwidth and the number of sessions. Without the API, the browser falls back to a public STUN server.

What it gave me

It is not a throwaway. It reuses pieces I already had: CSS classes, deployment scripts, bits of server code. It was put together almost entirely by assembly, and that is what interests me.

Building it gave me a method and a base for deploying a website quickly: a modular style sheet that is already ready, a deployment through git push, and scripts that do the rest. The next site can start from there instead of from scratch.

Limits

The counter’s search bar is written but disabled until the site has enough couples. Since contracts are shared by everyone, two strangers can end up writing on the same sheet: that is intended, but it means the content is not moderated. Call setup goes through PeerJS’s public server, not one of mine. I have not tested the video relay at scale, and the repository contains no tests.

Links