01 · Contexte & objectif
Suivre ses dépenses et ses revenus sans jamais connecter son compte bancaire à un service tiers : les données restent dans l’application, l’utilisateur les saisit. La saisie n’est pas le sujet — la projection l’est. Savoir ce que vaudront ses comptes dans dix ans suppose de rejouer le futur mois par mois.
02 · Contraintes
Le sujet allait bien au-delà du CRUD. Un compte porte un taux de rémunération annuel, lui-même soumis à un taux d’imposition : un compte-titres à 7 % taxé à 30 % ne se projette pas comme un Livret A à 1,7 % net. Dépenses et revenus sont ponctuels ou récurrents tous les N mois, bornés par des dates de début et de fin. S’y ajoutent les exceptions — modifier le montant d’une échéance sur une période donnée sans toucher au montant initial ni aux mois voisins.
Côté livraison : déploiement conteneurisé derrière un nom de domaine, certificat SSL valide, secrets hors du code source, XSS et injections SQL vérifiées, et une maquette Figma dont l’intégration devait être fidèle.
03 · Architecture
MVC maison en PHP 8.3, sans framework. Un front controller unique (public/index.php),
un routeur et les handlers HTTP dans App.php, un wrapper PDO au-dessus de SQLite,
et une couche de services par domaine métier — comptes, dépenses, revenus,
exceptions, utilisateurs — qui isole les règles de calcul des vues.
En développement, Docker assemble Nginx, PHP-FPM et MailHog, ce qui permet de tester les e-mails d’activation et de réinitialisation sans envoyer quoi que ce soit. La production tourne sur une composition distincte, derrière Nginx et Let’s Encrypt.
04 · Décisions techniques
Un MVC écrit à la main, parce que le sujet l’imposait. Ce n’était pas un choix : aucun framework autorisé, donc front controller, routeur, couche de services et wrapper PDO écrits un par un.
Le moteur de prévision. Un solde au 31/12/2035 n’est pas une formule fermée : il se calcule en rejouant les mois un par un, à la volée, sans table de résultats pré-calculés. À chaque pas, le moteur applique les échéances dues ce mois-là, puis la rémunération du compte nette de son imposition.
Les exceptions ne touchent jamais au montant de référence. Elles vivent dans leur propre table, et l’itération vérifie à chaque mois s’il en existe une pour l’échéance en cours : si oui c’est son montant qui s’applique, sinon celui de base. Le montant initial reste donc intact, et supprimer une exception suffit à revenir au comportement d’origine.
05 · Ce que j’en retire
Le moteur de prévision a été le point dur, et de loin. Le reste du projet est du CRUD ; la projection, elle, fait converger sur un même pas mensuel des règles qui n’ont rien à voir entre elles — récurrence tous les N mois, bornes de début et de fin, taux de rémunération, imposition, exceptions ponctuelles. Chacune est simple prise seule, c’est leur superposition sur le même mois qui est difficile à tenir juste.
01 · Context & goal
Track spending and income without ever connecting a bank account to a third-party service: the data stays in the application, entered by the user. Data entry isn’t the point — forecasting is. Knowing what your accounts will be worth in ten years means replaying the future month by month.
02 · Constraints
The brief went well beyond CRUD. An account carries an annual interest rate, itself subject to a tax rate: a securities account at 7% taxed at 30% doesn’t project like a savings account at 1.7% untaxed. Expenses and income are either one-off or recur every N months, bounded by start and end dates. On top of that sit exceptions — overriding a single instalment’s amount over a given period without altering the base amount or the surrounding months.
On delivery: containerised deployment behind a domain name, valid SSL certificate, secrets kept out of source control, XSS and SQL injection audited, and a Figma mockup the implementation had to match faithfully.
03 · Architecture
Hand-rolled MVC in PHP 8.3, no framework. A single front controller
(public/index.php), routing and HTTP handlers in App.php, a PDO wrapper over
SQLite, and one service per business domain — accounts, expenses, income,
exceptions, users — keeping the calculation rules out of the views.
In development, Docker wires up Nginx, PHP-FPM and MailHog, so activation and password-reset e-mails can be tested without sending anything. Production runs on a separate composition, behind Nginx and Let’s Encrypt.
04 · Technical decisions
A hand-written MVC, because the brief required it. Not a choice: no framework allowed, so front controller, router, service layer and PDO wrapper all written by hand, one at a time.
The forecasting engine. A balance on 31/12/2035 is not a closed-form formula: it is computed by replaying the months one by one, on the fly, with no table of pre-computed results. At each step the engine applies the instalments due that month, then the account’s interest net of its tax rate.
Exceptions never touch the base amount. They live in their own table, and the iteration checks each month whether one exists for the instalment at hand: if so its amount applies, otherwise the base one does. The original amount stays intact, and deleting an exception is enough to return to the default behaviour.
05 · Takeaways
The forecasting engine was the hard part, by a wide margin. The rest of the project is CRUD; the projection makes unrelated rules converge on a single monthly step — recurrence every N months, start and end bounds, interest rate, taxation, one-off exceptions. Each is simple on its own; keeping their overlap correct on the same month is what is difficult.