| @@ -1,116 +1,131 @@ |
| 1 | # Ex Ego | 1 | # Ex Ego |
| 2 | | 2 | |
| 3 | -**Ex Ego** — à l'oreille *ex aequo* (l'objectif : à égalité), à la lettre | 3 | +**Ex Ego** — à l'oreille *ex aequo* (l'objectif : à égalité), à l’écrit |
| 4 | -*ex-ego* (le moyen : on dépose l'ego et on mesure de bonne foi). | 4 | +*ex-ego* (le moyen : on dépose l'ego et on mesure de bonne foi). |
| 5 | | 5 | |
| 6 | Application web de comptage de temps par catégorie et de tâches partagées, en | 6 | Application web de comptage de temps par catégorie et de tâches partagées, en |
| 7 | équipe. Mobile-first (PWA), UI trilingue (français, anglais, allemand), rendu | 7 | équipe. Mobile-first (PWA), UI trilingue (français, anglais, allemand), rendu |
| 8 | -100 % côté serveur (le JavaScript n'existe qu'en amélioration progressive : | 8 | +100 % côté serveur, amélioration progressive en JavaScript. |
| 9 | -tout fonctionne par liens et formulaires). | 9 | + |
| | 10 | +Stack : Rust (axum, askama, sqlx), PostgreSQL, biscuit-auth. Aucun framework |
| | 11 | +front, une seule feuille de CSS. |
| | 12 | + |
| | 13 | +### Inspiration |
| 10 | | 14 | |
| 11 | L'inspiration vient de [Maydée](https://blog.mbadmb.com/lapplication-maydee/), | 15 | L'inspiration vient de [Maydée](https://blog.mbadmb.com/lapplication-maydee/), |
| 12 | l'application de l'association fondée par Julie Hebting pour rendre visible la | 16 | l'application de l'association fondée par Julie Hebting pour rendre visible la |
| 13 | répartition du travail domestique ([18h39](https://www.18h39.fr/changer-de-vie/solidarite-logement/mesurez-comment-les-taches-sont-reparties-dans-votre-couple-grace-a-cette-appli.html), | 17 | répartition du travail domestique ([18h39](https://www.18h39.fr/changer-de-vie/solidarite-logement/mesurez-comment-les-taches-sont-reparties-dans-votre-couple-grace-a-cette-appli.html), |
| 14 | [Magic Maman](https://www.magicmaman.com/maydee-l-appli-qui-peut-revolutionner-la-repartition-des-travaux-menagers,3598841.asp)). | 18 | [Magic Maman](https://www.magicmaman.com/maydee-l-appli-qui-peut-revolutionner-la-repartition-des-travaux-menagers,3598841.asp)). |
| 15 | Maydée ne semble malheureusement plus utilisable aujourd'hui (son domaine ne | 19 | Maydée ne semble malheureusement plus utilisable aujourd'hui (son domaine ne |
| 16 | -pointe même plus vers l'association) : Ex Ego est né du besoin de la | 20 | +pointe même plus vers l'association). |
| 17 | -remplacer. La fonctionnalité centrale est la même : **comparer le temps | 21 | + |
| 18 | -passé** sur les tâches du foyer (comme les créatrices de Maydée, on considère ici que le temps est la mesure la plus « juste » du travail domestique, si tout le monde est de bonne foi). | 22 | +Ex Ego a pour but de remplacer Maydée pour m’apporter une continuité. |
| 19 | -Pas d'objectif de 50-50 : une base objective pour en parler. | 23 | +On garde les mêmes fonctionnalités: |
| | 24 | +- Compter le temps d’une tâche |
| | 25 | +- Catégoriser le temps compté |
| | 26 | +- Visualiser la répartition du temps et des tâches. |
| | 27 | + |
| | 28 | +On laisse tomber les infos personnelle : CSP, notion de "Couple", nombre d’enfants… |
| | 29 | +J’imagine que Maydée voulait pouvoir faire des stats là-dessus, moi je m’en fiche. |
| | 30 | + |
| | 31 | +### But de l’application |
| 20 | | 32 | |
| 21 | Avoir de la *donnée* sur le temps passé aux tâches domestiques change la | 33 | Avoir de la *donnée* sur le temps passé aux tâches domestiques change la |
| 22 | -nature de la conversation : on ne débat plus de ressentis ni de souvenirs | 34 | +nature de la conversation : on ne débat plus de ressentis ni de souvenirs |
| 23 | (« j'ai l'impression de tout faire ») mais d'un relevé que chacun a constitué | 35 | (« j'ai l'impression de tout faire ») mais d'un relevé que chacun a constitué |
| 24 | de bonne foi. La répartition des tâches devient un sujet moins passionné et | 36 | de bonne foi. La répartition des tâches devient un sujet moins passionné et |
| 25 | plus apaisé (on regarde les chiffres ensemble, puis on décide ensemble). | 37 | plus apaisé (on regarde les chiffres ensemble, puis on décide ensemble). |
| 26 | | 38 | |
| 27 | -Ex Ego n'a pas vocation à devenir un SaaS pour l'instant : la création de | 39 | +Ex Ego n'a pas vocation à devenir un SaaS pour l'instant : la création de |
| 28 | comptes est manuelle (en ligne de commande), pas d'e-mail, pas d'inscription, | 40 | comptes est manuelle (en ligne de commande), pas d'e-mail, pas d'inscription, |
| 29 | rien. Si tu veux essayer, je peux partager un compte sur une instance de | 41 | rien. Si tu veux essayer, je peux partager un compte sur une instance de |
| 30 | démo à la demande (ouvre une issue). | 42 | démo à la demande (ouvre une issue). |
| 31 | | 43 | |
| 32 | -Stack : Rust (axum, askama, sqlx), PostgreSQL, biscuit-auth. Aucun framework | 44 | +#### Exemples |
| 33 | -front, une seule feuille de CSS. | 45 | + |
| 34 | - | 46 | +En utilisant Maydée puis Ex Ego, nous avons remarqué différentes choses chez nous: |
| 35 | -> **English**: team time tracker and shared todo list, inspired by the | 47 | + |
| 36 | -> French app Maydée, which no longer seems to be available (Ex Ego was built | 48 | +- Une personne pensait que l’autre ne faisait pas grand chose, car l’autre n’informait pas |
| 37 | -> to replace it). The core idea is comparing *time spent* on household tasks | 49 | + forcément des tâches effectuées |
| 38 | -> (the fairest measure of domestic work, as long as everyone acts in good | 50 | +- Ça apporte un petit côté _gamification_ où on veut essayer de rattraper l’autre |
| 39 | -> faith). Log time per category, run a timer, take dated tasks and | 51 | +- On s’est rendu compte qu’un partage des tâches "statique" pouvait être trompeur : faire |
| 40 | -> reschedule them at their observed rhythm, and read stacked-bar statistics | 52 | + à manger = 1 heure, faire la vaisselle du même repas < 15 minutes. |
| 41 | -> per member. Having *data* about time spent on housework changes the nature | 53 | +- Si A fait une tâche mais pas jusqu’au bout, B est moins agacé·e car au pire iel finit la |
| 42 | -> of the conversation: instead of debating feelings and recollections, you | 54 | + tâche en mesurant. Et vice-versa. |
| 43 | -> look at numbers gathered in good faith (a calmer, less heated way to talk | 55 | +- Parfois, si A a beaucoup d’heures d’avance, iel se sent plus légitime à faire une |
| 44 | -> about who does what). Not a SaaS for now: accounts are created manually | 56 | + pause. |
| 45 | -> from the command line (no e-mail, no sign-up); a demo account can be | 57 | + |
| 46 | -> shared on request. Mobile-first | 58 | +### English |
| 47 | -> PWA, fully server-rendered (JavaScript is progressive enhancement only), | 59 | + |
| 48 | -> trilingual (FR/EN/DE, language is a per-user setting), with an optional | 60 | +Team time tracker and shared todo list. |
| 49 | -> high-contrast black-and-white theme (per-user too, charts included). Rust | 61 | +The core idea is comparing *time spent* on household tasks |
| 50 | -> (axum, askama, sqlx), PostgreSQL, no front-end framework. | 62 | +(the fairest measure of domestic work, as long as everyone acts in good |
| 51 | - | 63 | +faith). Log time per category, run a timer, take dated tasks and |
| 52 | -> **Deutsch**: Zeiterfassung und geteilte Aufgabenliste fürs Team, | 64 | +reschedule them at their observed rhythm, and read stacked-bar statistics |
| 53 | -> inspiriert von der französischen App Maydée, die nicht mehr verfügbar zu | 65 | +per member. Having *data* about time spent on housework changes the nature |
| 54 | -> sein scheint (Ex Ego wurde als Ersatz gebaut). Kern der Idee ist der | 66 | +of the conversation: instead of debating feelings and recollections, you |
| 55 | -> Vergleich der *aufgewendeten Zeit* für Hausarbeit (das fairste Maß für | 67 | +look at numbers gathered in good faith (a calmer, less heated way to talk |
| 56 | -> häusliche Arbeit, solange alle guten Willens sind). Zeiten pro Kategorie | 68 | +about who does what). Not a SaaS for now: accounts are created manually |
| 57 | -> erfassen, Timer laufen lassen, datierte Aufgaben übernehmen und im | 69 | +from the command line (no e-mail, no sign-up); a demo account can be |
| 58 | -> beobachteten Rhythmus neu planen, Statistiken pro Mitglied lesen. *Daten* | 70 | +shared on request. Mobile-first |
| 59 | -> über die für Hausarbeit aufgewendete Zeit verändern das Gespräch: Statt | 71 | +PWA, fully server-rendered (JavaScript is progressive enhancement only), |
| 60 | -> über Gefühle und Erinnerungen zu streiten, schaut man gemeinsam auf in | 72 | +trilingual (FR/EN/DE, language is a per-user setting), with an optional |
| 61 | -> gutem Glauben erfasste Zahlen (eine ruhigere, sachlichere Art, über die | 73 | +high-contrast black-and-white theme (per-user too, charts included). Rust |
| 62 | -> Aufgabenverteilung zu sprechen). Vorerst kein SaaS: Konten werden manuell | 74 | +(axum, askama, sqlx), PostgreSQL, no front-end framework. |
| 63 | -> über die Kommandozeile angelegt (keine E-Mail, keine Registrierung); ein | 75 | + |
| 64 | -> Demo-Konto gibt es auf Anfrage. | 76 | +### Deustch |
| 65 | -> Mobile-first-PWA, vollständig serverseitig gerendert (JavaScript nur als | 77 | + |
| 66 | -> Progressive Enhancement), dreisprachig (FR/EN/DE, die Sprache ist eine | 78 | +Zeiterfassung und geteilte Aufgabenliste fürs Team. |
| 67 | -> Einstellung pro Benutzer), mit optionalem kontrastreichem | 79 | +Kern der Idee ist der Vergleich der *aufgewendeten Zeit* für Hausarbeit (das fairste Maß für |
| 68 | -> Schwarz-Weiß-Thema (ebenfalls pro Benutzer, inklusive Diagramme). Rust | 80 | +häusliche Arbeit, solange alle guten Willens sind). Zeiten pro Kategorie |
| 69 | -> (axum, askama, sqlx), PostgreSQL, ohne Frontend-Framework. | 81 | +erfassen, Timer laufen lassen, datierte Aufgaben übernehmen und im |
| | 82 | +beobachteten Rhythmus neu planen, Statistiken pro Mitglied lesen. *Daten* |
| | 83 | +über die für Hausarbeit aufgewendete Zeit verändern das Gespräch: Statt |
| | 84 | +über Gefühle und Erinnerungen zu streiten, schaut man gemeinsam auf in |
| | 85 | +gutem Glauben erfasste Zahlen (eine ruhigere, sachlichere Art, über die |
| | 86 | +Aufgabenverteilung zu sprechen). Vorerst kein SaaS: Konten werden manuell |
| | 87 | +über die Kommandozeile angelegt (keine E-Mail, keine Registrierung); ein |
| | 88 | +Demo-Konto gibt es auf Anfrage. |
| | 89 | +Mobile-first-PWA, vollständig serverseitig gerendert (JavaScript nur als |
| | 90 | +Progressive Enhancement), dreisprachig (FR/EN/DE, die Sprache ist eine |
| | 91 | +Einstellung pro Benutzer), mit optionalem kontrastreichem |
| | 92 | +Schwarz-Weiß-Thema (ebenfalls pro Benutzer, inklusive Diagramme). Rust |
| | 93 | +(axum, askama, sqlx), PostgreSQL, ohne Frontend-Framework. |
| 70 | | 94 | |
| 71 | ## Fonctionnalités | 95 | ## Fonctionnalités |
| 72 | | 96 | |
| 73 | -- **Saisie de temps** en deux étapes : choisir une catégorie, puis durée | 97 | +- **Saisie de temps**: choisir une catégorie, puis durée |
| 74 | - (steppers ± 5 min, presets) et date. Modification et suppression ensuite. | 98 | + (steppers ± 5 min, presets) et date. Un écran "paramètres" permet de modifier/supprimer. |
| 75 | -- **Minuteur** : démarrer/arrêter une mesure, enregistrée dans la catégorie | 99 | +- **Minuteur** : démarrer/arrêter une mesure, enregistrée dans la catégorie |
| 76 | - choisie ; pastille sur l'icône de l'app (Badging API) tant qu'une mesure | 100 | + choisie. |
| 77 | - attend. | 101 | +- **Statistiques** : 6 graphiques (semaine en équipe, puis comparatif par tâche pour : jour, semaine ISO, mois, année, tout |
| 78 | -- **Statistiques** : 4 graphiques empilés (semaine ISO, mois, année, tout | 102 | + l'historique), une colonne par membre, détail par segment en pop up. |
| 79 | - l'historique), une colonne par membre, détail par segment en bottom sheet. | 103 | +- **Todo list d'équipe** : tâches datées rattachées à une catégorie ; |
| 80 | -- **Todo list d'équipe** : tâches datées rattachées à une catégorie ; | 104 | + n'importe quel membre peut prendre une tâche (une action permet de se verrouiller une |
| 81 | - n'importe quel membre peut prendre une tâche (verrou : seul le preneur la | 105 | + tâche), la marquer faite en enregistrant un |
| 82 | - termine ou la modifie), la marquer faite en enregistrant (ou non) un | 106 | + temps ou non, puis la reprogrammer à la date proposée. Assignations purement informatives avec filtre |
| 83 | - temps, puis la reprogrammer à la date proposée (médiane des intervalles | 107 | + « Mes tâches ». Bloc « À venir » pour les tâches futures. |
| 84 | - entre complétions). Assignations purement informatives avec filtre | 108 | +- **Équipes** : multi-équipes par utilisateur, équipe active par appareil |
| 85 | - « Mes tâches », bloc « À venir » pour les tâches futures. | | |
| 86 | -- **Équipes** : multi-équipes par utilisateur, équipe active par appareil | | |
| 87 | (cookie), invitations par username, couleur d'équipe dérivée de son id. | 109 | (cookie), invitations par username, couleur d'équipe dérivée de son id. |
| 88 | -- **Comptes** : authentification par biscuit en cookie (~6 mois), | 110 | +- **Comptes** : session par biscuit en cookie (~6 mois), |
| 89 | révocation au logout, CSRF stateless, argon2id. | 111 | révocation au logout, CSRF stateless, argon2id. |
| 90 | -- **Accessibilité** : WCAG 2.1/2.2 AA (zéro violation axe sur les 12 | 112 | +- **Accessibilité** : WCAG 2.1/2.2 AA (zéro violation axe sur les 12 |
| 91 | - écrans : contrastes, cibles 24 px, landmarks, focus des sheets, Échap). | 113 | + écrans : contrastes, cibles 24 px, landmarks, focus des sheets, Échap). |
| 92 | -- **Contraste élevé** : un thème noir et blanc, réglage **par utilisateur** | 114 | +- **Contraste élevé** : un thème noir et blanc, réglage **par utilisateur** |
| 93 | (Réglages → Affichage), pour les écrans très sombres ou les filtres de | 115 | (Réglages → Affichage), pour les écrans très sombres ou les filtres de |
| 94 | - lumière chaude — graphiques compris (palette en niveaux de gris). | 116 | + lumière chaude. |
| 95 | -- **Trilingue** : français, anglais, allemand. La langue est un réglage | 117 | +- **Trilingue** : français, anglais, allemand. La langue est un réglage |
| 96 | - **par utilisateur** (page Réglages), stocké en base : le choix suit le | 118 | + **par utilisateur** (page Réglages). Langue par défaut à la création |
| 97 | - compte sur tous les appareils. Français par défaut à la création, | | |
| 98 | modifiable par la variable d'environnement `DEFAULT_LANG`. | 119 | modifiable par la variable d'environnement `DEFAULT_LANG`. |
| 99 | | 120 | |
| 100 | -## Documentation | | |
| 101 | - | | |
| 102 | -Un site de documentation trilingue décrit chaque écran, son intention, et | | |
| 103 | -raconte trois usages réels : `docs/site-documentation` (site Zola, publié sur | | |
| 104 | -[ex-ego.durillon.family/documentation](https://ex-ego.durillon.family/documentation)). | | |
| 105 | - | | |
| 106 | ## Captures d'écran | 121 | ## Captures d'écran |
| 107 | | 122 | |
| 108 | | | | | 123 | | | | |
| 109 | |:---:|:---:| | 124 | |:---:|:---:| |
| 110 | |  |  | | 125 | |  |  | |
| 111 | -| *Connexion* | *Ajouter : choisir la catégorie* | | 126 | +| *Connexion* | *Ajouter : choisir la catégorie* | |
| 112 | |  |  | | 127 | |  |  | |
| 113 | -| *Ajouter : durée et date* | *Statistiques d'équipe* | | 128 | +| *Ajouter : durée et date* | *Statistiques d'équipe* | |
| 114 | |  |  | | 129 | |  |  | |
| 115 | | *Todo list (verrou, assignations)* | *Complétion en bottom sheet* | | 130 | | *Todo list (verrou, assignations)* | *Complétion en bottom sheet* | |
| 116 | |  |  | | 131 | |  |  | |
| @@ -118,8 +133,9 @@ raconte trois usages réels : `docs/site-documentation` (site Zola, publié sur |
| 118 | | 133 | |
| 119 | ## Ligne de commande | 134 | ## Ligne de commande |
| 120 | | 135 | |
| 121 | -Le binaire sert aussi d'outil d'administration (les comptes ne se créent que | 136 | +Les comptes ne se créent que par CLI. |
| 122 | -par CLI). Toutes les commandes appliquent les migrations au démarrage et | 137 | +Le binaire sert aussi d'outil d'administration. |
| | 138 | +Toutes les commandes appliquent les migrations au démarrage et |
| 123 | lisent la base via `POSTGRESQL_ADDON_URI` (prioritaire) ou `DATABASE_URL`. | 139 | lisent la base via `POSTGRESQL_ADDON_URI` (prioritaire) ou `DATABASE_URL`. |
| 124 | | 140 | |
| 125 | ```bash | 141 | ```bash |
| @@ -132,14 +148,14 @@ exego user join <username> --team <équipe> # ajoute un compte existant |
| 132 | # à une équipe | 148 | # à une équipe |
| 133 | ``` | 149 | ``` |
| 134 | | 150 | |
| 135 | -Variables d'environnement du serveur : | 151 | +Variables d'environnement du serveur : |
| 136 | | 152 | |
| 137 | | Variable | Rôle | | 153 | | Variable | Rôle | |
| 138 | |---|---| | 154 | |---|---| |
| 139 | | `POSTGRESQL_ADDON_URI` ou `DATABASE_URL` | connexion PostgreSQL (TLS imposé côté client quoi que dise l'URL) | | 155 | | `POSTGRESQL_ADDON_URI` ou `DATABASE_URL` | connexion PostgreSQL (TLS imposé côté client quoi que dise l'URL) | |
| 140 | -| `BISCUIT_PRIVATE_KEY` | clé privée racine (hex, via `keygen`) | | 156 | +| `BISCUIT_PRIVATE_KEY` | clé privée racine (à générer une fois avec `exego keygen`) | |
| 141 | | `PORT` | port d'écoute (défaut 8080) | | 157 | | `PORT` | port d'écoute (défaut 8080) | |
| 142 | -| `DEFAULT_LANG` | langue des nouveaux comptes et des pages anonymes : `fr` (défaut), `en` ou `de` | | 158 | +| `DEFAULT_LANG` | langue des nouveaux comptes et des pages anonymes : `fr` (défaut), `en` ou `de` | |
| 143 | | 159 | |
| 144 | ### Développement local | 160 | ### Développement local |
| 145 | | 161 | |
| @@ -150,12 +166,12 @@ BISCUIT_PRIVATE_KEY=$(cargo run -- keygen | grep -o '[0-9a-f]\{64\}') \ |
| 150 | PORT=8090 cargo run -- serve | 166 | PORT=8090 cargo run -- serve |
| 151 | ``` | 167 | ``` |
| 152 | | 168 | |
| 153 | -Audit d'accessibilité récurrent : voir `a11y/audit.mjs` (axe-core + Chrome | 169 | +Audit d'accessibilité : voir `a11y/audit.mjs` (axe-core + Chrome |
| 154 | headless sur les 12 écrans, exit 1 à la moindre violation sérieuse). | 170 | headless sur les 12 écrans, exit 1 à la moindre violation sérieuse). |
| 155 | | 171 | |
| 156 | ## Déployer sur Clever Cloud | 172 | ## Déployer sur Clever Cloud |
| 157 | | 173 | |
| 158 | -Prérequis : [clever-tools](https://www.clever-cloud.com/doc/clever-tools/) | 174 | +Prérequis : [clever-tools](https://www.clever-cloud.com/doc/clever-tools/) |
| 159 | (`npm i -g clever-tools`) et `clever login`. | 175 | (`npm i -g clever-tools`) et `clever login`. |
| 160 | | 176 | |
| 161 | ```bash | 177 | ```bash |
| @@ -167,7 +183,7 @@ clever addon create postgresql-addon exego-db --plan dev |
| 167 | clever service link-addon exego-db | 183 | clever service link-addon exego-db |
| 168 | # → l'app reçoit POSTGRESQL_ADDON_URI automatiquement | 184 | # → l'app reçoit POSTGRESQL_ADDON_URI automatiquement |
| 169 | | 185 | |
| 170 | -# 3. Générer et poser la clé biscuit (à garder précieusement : | 186 | +# 3. Générer et poser la clé biscuit (à garder précieusement : |
| 171 | # la changer invalide toutes les sessions) | 187 | # la changer invalide toutes les sessions) |
| 172 | clever env set BISCUIT_PRIVATE_KEY "$(cargo run -- keygen | grep -o '[0-9a-f]\{64\}')" | 188 | clever env set BISCUIT_PRIVATE_KEY "$(cargo run -- keygen | grep -o '[0-9a-f]\{64\}')" |
| 173 | | 189 | |
| @@ -182,16 +198,17 @@ cargo run -- team add "Maison" |
| 182 | cargo run -- user add alice --team "Maison" | 198 | cargo run -- user add alice --team "Maison" |
| 183 | ``` | 199 | ``` |
| 184 | | 200 | |
| 185 | -Notes : | 201 | +Notes : |
| 186 | | 202 | |
| 187 | - Le fichier `.clever.json` créé par `clever create`/`clever link` contient | 203 | - Le fichier `.clever.json` créé par `clever create`/`clever link` contient |
| 188 | - les identifiants de l'app : il est **ignoré par git**, ne pas le committer. | 204 | + les identifiants de l'app. Il est **ignoré par git** dans ce repo public, mais rien |
| 189 | -- Dimensionnement éprouvé : build flavor `L`, run flavor `nano` | 205 | + n’empêche de le committer. |
| | 206 | +- Dimensionnement éprouvé : build flavor `L`, run flavor `nano` |
| 190 | (`clever scale --build-flavor L --flavor nano`). | 207 | (`clever scale --build-flavor L --flavor nano`). |
| 191 | -- Le plan PostgreSQL DEV est limité à 5 connexions : le pool de l'app est | 208 | +- Le plan PostgreSQL DEV est limité à 5 connexions : le pool de l'app est |
| 192 | calibré à 2 pour survivre à la cohabitation bleu-vert d'un déploiement. | 209 | calibré à 2 pour survivre à la cohabitation bleu-vert d'un déploiement. |
| 193 | - Écrire les migrations pour qu'elles passent sur les données déjà en | 210 | - Écrire les migrations pour qu'elles passent sur les données déjà en |
| 194 | - production : l'ancien et le nouveau binaire cohabitent quelques secondes. | 211 | + production : l'ancien et le nouveau binaire cohabitent quelques secondes. |
| 195 | | 212 | |
| 196 | ## Licence | 213 | ## Licence |
| 197 | | 214 | |