Portrait of Patrice GADEGBEPatrice GADEGBE

myFenyx

myFenyx is the internal application of Fenyx Group's consultants, in which each of them declares the actions that earn them points, follows their wallet and the ranking, then exchanges their points for gifts.

Role
Author of the mobile application and main author of the API
Period
From January 2023 to today
Status
In service. In service, published on Google Play and on the App Store
Technologies
Django 3.2, Django REST Framework, Celery, PostgreSQL, Redis, Flutter, flutter_bloc
Repositories
Two
Architecture of myFenyxThe Flutter application calls a Django API placed behind nginx. The API relies on PostgreSQL for the data and on Redis for the cache and the task queue, and calls on third-party services for notifications, sign-in and email.ApplicationFlutter, flutter_blociOS and AndroidAPIDjango 3.2, REST Frameworknginx, Daphne, CeleryPostgreSQL 15dataRediscache, rate limitingtask queueHTTPS, tokenoutboundThird-party servicesnotifications, directoryemail
Figure 1. Architecture of myFenyx. The dashed line stands for the notifications, which go from the server to the phones.

This study complements the article myFenyx: turning a manual HR process into a real application, which sets out the intent of the project. It keeps to the architecture and to a few technical choices, since the rules specific to the company have no place here.

Context

The rewards scheme of Fenyx Group was kept by hand by human resources, and a consultant had to phone to find out their balance. From January 2023, myFenyx replaced it with a mobile application and an administration interface, from which human resources read the declarations, credit the points and process the exchange requests. The application then extended to the group’s news and events, with their notifications.

Problem

An internal economy requires exact balances and a ranking that can be read without delay, whereas points are awarded by year and spent long after they were earned. An exchange request also had to take nothing from a consultant until it had been validated, and the sign-in had to suit agencies that do not all have the same directory.

Answer

A wallet per year, a precomputed ranking

Credits and debits are two separate tables, each row of which carries its year, and the balance is obtained by difference. A third table keeps, for each consultant and each year, their points, their spending, their balance and their rank; it is rebuilt when the administration changes the data, and the ranking endpoint reads nothing else. The application thus displays the ranking without the server having to compute it on demand.

A two-step exchange

A consultant’s request checks that their balance covers their basket, but debits nothing, and it can still be cancelled. The debit takes place only when an administrator processes the request, inside a transaction, drawing first on the oldest year and writing one spending row per year drawn on. This order, first in, first out, is the one the article describes.

A sign-in decided by the server

Each agency declares the sign-in methods it accepts, namely the company’s Microsoft directory or a one-time code sent by email, and the application chains its screens accordingly. The code path was rewritten in July 2026: the code is drawn at random, only its hash is kept, it is used only once, attempts are counted, and the response is identical whether the account exists or not. Rate limiting relies on Redis, so that it holds whichever process receives the request.

Notifications that are kept

A notification is first a row in the database, created for each consultant concerned by an event or a news item, and it is the saving of that row that triggers the sending to the phone. It carries a type code and an identifier, which the application translates into a destination. Lastly, the build number of the application is derived from the number of commits, then recorded in a git tag, so that a version in the store can always be tied to a state of the repository.

Limits and outlook

The tests cover only the sign-in by code, six cases in all, and nothing yet verifies the wallet, the debit order or the ranking, which are nonetheless the heart of the application. The ranking is moreover rebuilt in full and synchronously on every change, which suits the current headcount and will have to move to a background task if it grows.

A WebSocket channel was prepared on the server side without being put into service, the application refreshing itself when it receives a notification. The integration pipelines are not wired up and releases still leave from my machine. Lastly, the API remains on Django 3.2, whose upgrade has to be planned, and the history of the schema is not under version control, which will have to be corrected first.

Back to the work