Smart notifications
HOCO's document 03 (Smart Notifications) treated as a change request: the 24 notification types, the Notification Centre, the action button, the Top 3 and the promotion tabs, each with its trigger, audience, channel, group, action and release, plus anti-fatigue rules, data and API impact and the French and Arabic copy.
Source and status
| Item | Value |
|---|---|
| Document | DOCUMENT 03 : SMART NOTIFICATIONS, written by HOCO in Algerian Arabic and French |
| Received | 18 October 2026 |
| Status | Change request against the cahier (cahier §8 Notifications, §14 phases). It is accepted into the specification with the release placement below. V1 items fit the existing modules. V2 items wait for the loyalty engine. Later items are new modules and need a separate estimate (validation sheet, Clause de périmètre) |
| Requirements | V1: NOT-09 to NOT-17 and PRM-07. V2: NOT-18, PRM-08, LOY-06, LOY-07 |
| Decisions | D-39 to D-44, all Defaulted (18 Oct 2026) |
| Plan | DES-23, SRV-39, SRV-40, DSH-14, WEB-06, MRA-11 |
| Related | Notifications matrix (event rows, copy, quiet hours, caps) · scope · jobs |
The client's principle
The document opens with four goals: keep the app present in the reseller's mind (« يخلي التطبيق ديما حاضر في بالو »), increase the number of orders, make sure no offer is missed, and help the reseller run their shop better. It states the rule « كل Notification لازم يكون عندها هدف تجاري »: every notification must have a commercial goal. It ends with a second rule the client is "100 % convinced" of: « كل Notification لازم يكون فيها زر Action », every notification carries an action button.
The specification turns this into three rules:
- Every reseller notification has a group (
NotificationGroup, the section of the Notification Centre) and an action (action { label, deepLink }). The transactional notifications already in the matrix get one too (NOT-10). - Smart notifications are rule-based and computed by the server from data the platform already holds: catalog, availability, prices, carts, orders, favorites, promotions. They are never sent by hand, except the commercial push, where HOCO picks the product and the audience.
- Smart notifications are commercial (
PROMOTIONALcategory). They obey the anti-fatigue rules so that the Notification Centre stays useful and the reseller does not mute the app. Two decisions of 17 October still apply: resellers never see a stock quantity (STK-07), and guests receive no notification.
Release placement
| Release | Items | Why |
|---|---|---|
| V1 | SN-01 Nouvel arrivage · SN-02 Retour en stock · SN-03 Stock faible · SN-04 Promotion · SN-12 Smart reminder (rule-based) · SN-14 Produit complémentaire (configured pairs) · SN-17 Produit tendance (weekly top seller) · SN-18 Flash sale (countdown, 2 h to 48 h) · SN-19 Nouveau catalogue · SN-20 Panier abandonné · SN-21 Alerte prix · SN-23 Notification commerciale · SN-25 Notification Centre (6 groups) · SN-26 Action button · SN-28 tabs Promotions and Flash Sales | Every trigger reads data that V1 modules already hold: catalog (SRV-11), inventory availability (SRV-13), cart (SRV-15), orders (SRV-16), promotions (SRV-19), price history, favorites and announcements. The only new mechanisms are scheduled scans and per-reseller rules on the existing notification pipeline (SRV-08). The work costs about 6.5 working days across the lanes. The plan shows the effect on the schedule |
| V2 | SN-05 Double points · SN-06 Nouveau niveau · SN-07 Missions (commercial, interaction, challenge, surprise) · SN-08 Mission terminée · SN-09 Cadeau disponible · SN-15 Anniversaire d'inscription · SN-16 Objectif presque atteint (next level) · SN-22 Missions personnalisées · SN-24 Challenge du mois · SN-27 Top 3 revendeurs du mois · SN-28 tab Offres exclusives (by level) | All of them need points, levels or rewards. The loyalty programme is V2 (LOY-01 to LOY-05, D-16), built in SRV-30. They plug into the V1 groups, actions and caps without changing them |
| Later / to decide | SN-10 HOCO Academy (videos) · SN-11 Quiz · SN-13 Suggestions IA (bought together) · the Academy missions (watch videos, pass a quiz) · the Daily / Weekly / Monthly Mission cadence · the product-review mission | New modules that the cahier does not have: video hosting and a learning module (D-40), product reviews, and a recommendation model fed by V2 advanced analytics (ANA-06, D-41). The cadence of missions is a loyalty-policy choice made with the V2 engine |
The ACADEMY group exists in the enum from V1, so the Notification Centre keeps its six sections. Until the module exists the section is hidden (NOT-09).
Catalogue
Conventions used in the table:
- Channels:
IN_APPis the inbox row, shown in the Notification Centre.PUSHgoes to the reseller app; the reseller web has no web push in V1 and relies on the inbox and the live stream. No smart notification uses SMS: none meets the critical SMS rule, and marketing by SMS needs a prior opt-in (Law 18-07). The WhatsApp Business templates of V2 (NOT-08) are the channel to consider for SN-18 and SN-20 later. - Category is the preference category (
NotificationCategory). Group is the section of the Notification Centre (NotificationGroup). - Recipients are always active, validated resellers whose account can order (
store.canOrder) and who can see the product under its visibility rules (CAT-05). Guests, pending and suspended accounts receive nothing. - Deep links are proposals, like the rest of the route table. The reseller app and the reseller web use the same paths.
- Settings in
codeare proposals for the settings catalogue. The defaults come from D-39 to D-44.
V1 types
| Id | Name (client) | Trigger (rule) | Recipients | Channels | Category · group | Action (label → deep link) | Release · dependencies |
|---|---|---|---|---|---|---|---|
| SN-01 | Nouvel Arrivage | A product is published for the first time (Product.publishedAt set; status ACTIVE with at least one variant IN_STOCK), with the BO-28 box « Annoncer comme nouveauté » ticked (on by default). Job smart.newArrivalsDigest at 10:00 and 16:00 groups the products published since the last run | Every eligible reseller who can see the product | IN_APP · PUSH | PROMOTIONAL · NEW_PRODUCTS | « Commander maintenant » → RA-14 / RW-04 /products/{productId}; grouped (2 or more products) → RA-12 /catalog?tab=new | V1 · SRV-11, SRV-40 |
| SN-02 | Retour en Stock | The availability of a variant changes OUT_OF_STOCK → IN_STOCK (available quantity goes from 0 to above 0 in the inventory module). The variant must have stayed OUT_OF_STOCK for at least smart.restockMinOutHours (default 24 h), so that a correction does not trigger it | Only targeted resellers (the client's « ماشي كامل التجار »): those who ordered the variant in the last smart.restockLookbackDays (default 90, D-43) on an order that was not refused or cancelled, those who have the product in their favorites, and those whose cart holds the variant with the OUT_OF_STOCK issue | IN_APP · PUSH | PROMOTIONAL · NEW_PRODUCTS | « Commander maintenant » → /products/{productId}?variantId={variantId} | V1 · SRV-13, SRV-16, SRV-11 (favorites), SRV-15 |
| SN-03 | Stock Faible | The available stock of an IN_STOCK variant falls to or below its alert threshold, the same threshold as the staff stock.low alert (default 20, D-02). It fires once, then rearms only when the stock goes back above the threshold. No quantity is ever shown: the message says the quantity is limited, and the product page keeps « En stock » (STK-07) | Resellers who have the product in favorites or the variant in their cart, and resellers who ordered the variant at least twice in the last 90 days | IN_APP · PUSH | PROMOTIONAL · NEW_PRODUCTS | « Commander maintenant » → /products/{productId}?variantId={variantId} | V1 · SRV-13, SRV-16 |
| SN-04 | Promotion (offre normale) | Existing event promotion.started: a promotion becomes ACTIVE with « Notifier les revendeurs » ticked in BO-50. It covers clearance (déstockage), seasonal offers, back to school, Ramadan and year-end. The offer lasts until its end date or until its stock cap is consumed (PRM-04) | audience: resellers targeted by the promotion (PRM-02) | IN_APP · PUSH | PROMOTIONAL · PROMOTIONS | « Voir l'offre » → RA-25 / RW-10 /promotions/{promotionId} | V1 · SRV-19 (exists) |
| SN-12 | Smart Reminder | Rule-based on purchase cadence, not AI. For each reseller and leaf sub-category with at least 3 orders in the last 180 days, the median interval between those orders is the cadence. The reminder fires when the days since the last order containing that sub-category reach the cadence + smart.reorderGraceDays (default 1). Example: a weekly buyer of cables gets it on day 8. One reminder per sub-category and cycle; none when the cart already holds that sub-category. Job smart.reorderReminders runs daily at 09:30 | The reseller concerned | IN_APP · PUSH | PROMOTIONAL · SUGGESTIONS | « Commander à nouveau » → RA-22 / RW-09 /orders/{lastOrderId}?reorder=1, which opens the existing reorder sheet filtered on the sub-category | V1 · SRV-16, SRV-40 |
| SN-14 | Produit Complémentaire | Configured pairs. Each product may list up to 5 complementary products in BO-28 (« Produits complémentaires », ProductComplement). Example: a phone case gets tempered glass. The day after an order containing the product is confirmed (VALIDATED), job smart.complementSuggestions at 10:30 picks the first complement by position. That complement must be IN_STOCK, visible to the reseller, and not ordered by the reseller in the last 60 days. At most one per order | The reseller who placed the order | IN_APP · PUSH | PROMOTIONAL · SUGGESTIONS | « Voir le produit » → /products/{complementProductId} | V1 · SRV-11, SRV-16, SRV-39 |
| SN-17 | Produit Tendance | Job smart.trendingWeekly, Sunday at 09:00. It finds the product with the most units on confirmed orders over the previous 7 days, nationally, IN_STOCK, with at least 5 distinct buyers. Ties go to the larger number of buyers | Eligible resellers who did not order that product in the last 30 days | IN_APP · PUSH | PROMOTIONAL · NEW_PRODUCTS | « Voir le produit » → /products/{productId} | V1 · SRV-16, SRV-40 |
| SN-18 | Flash Sale (vente flash) | A promotion flagged isFlashSale becomes ACTIVE (job promotions.applySchedule). A flash sale lasts from 2 h to 48 h between startsAt and endsAt (validated in BO-50). The apps show a countdown computed from the server time (PRM-07). Typical uses: move stock fast, more orders in a short window, clear a limited quantity, special occasions | audience of the promotion | IN_APP · PUSH (high priority, TTL = the time left) | PROMOTIONAL · PROMOTIONS | « Commander maintenant » → RA-24 / RW-10 /promotions/{promotionId} | V1 · SRV-19, SRV-39 |
| SN-19 | Nouveau Catalogue | HOCO publishes a new edition of its catalogue in BO-57 (announcement of kind NEW_CATALOGUE). It carries a PDF file (CATALOG_PDF), optionally a category or a brand to open, and a cover image | audience of the announcement (default: every reseller) | IN_APP · PUSH | PROMOTIONAL · NEW_PRODUCTS | « Voir le catalogue » → RA-26 announcement sheet /messages/{announcementId} with the PDF link, or RA-12 /catalog?categoryId= when a category is set | V1 · SRV-24, SRV-39 |
| SN-20 | Panier Abandonné | The reseller's cart holds at least one line, its last change (Cart.updatedAt) is more than smart.abandonedCartDelayHours old (default 2, D-44), and no checkout happened since. It is sent once per cart version: any change to the cart resets it, and a checkout cancels a pending reminder. At most one per reseller per 24 h. Job smart.abandonedCarts runs every 15 minutes | The reseller | IN_APP · PUSH | PROMOTIONAL · SUGGESTIONS | « Finaliser ma commande » → RA-17 / RW-06 /cart | V1 · SRV-15, SRV-40 |
| SN-21 | Alerte Prix | A PriceChange lowers the price of a variant for a customer type by at least smart.priceDropMinPercent (default 5 %). Promotions are excluded because they have their own notification. Price increases are never notified | Resellers of that customer type who have the product in favorites, hold the variant in their cart, or ordered it in the last 90 days | IN_APP · PUSH | PROMOTIONAL · PROMOTIONS | « Voir le produit » → /products/{productId}?variantId={variantId} | V1 · SRV-12, SRV-40 |
| SN-23 | Notification Commerciale (HOCO's own idea) | The back-office picks a product (or a promotion, category or brand), an audience, a message and a send time in BO-57 (announcement of kind COMMERCIAL_PUSH, permission communication.validate). The editor shows how many resellers get the push and how many get the inbox entry only because of the caps | audience: wilayas, segments, customer types, named resellers, or buyers of a category in the last N days | IN_APP · PUSH | PROMOTIONAL · PROMOTIONS | Editable, default « Commander maintenant » → /products/{productId} (or /promotions/{id}, /catalog?categoryId=, /catalog?brandId=) | V1 · SRV-24, SRV-39, DSH-14 |
| SN-25 | Centre de Notifications | Not an event. It is a section of the home page (RA-09, RW-02) and the grouped inbox (RA-26, RW-11) with six groups, in the client's colours: Urgent (red), Promotions (orange), Nouveautés (green), Points et niveaux (blue), Academy (purple), Suggestions (star). Each group shows its unread count and its latest items. It replaces pop-ups (the client: the reseller finds everything in order and does not feel harassed) | Every signed-in reseller | — | URGENT holds the TRANSACTIONAL and SECURITY notifications and urgent announcements | Tapping a group opens RA-26 / RW-11 /notifications?group={group} | V1 · NOT-09; SRV-39, MRA-11, WEB-06, DES-23 |
| SN-26 | Bouton Action | Every reseller notification has an action with a French label and a deep link. The inbox and the Notification Centre render it as a button. On Android the push carries it as a notification action, and a tap on the body opens the same link | — | — | — | Defaults for the existing events: below | V1 · NOT-10 |
| SN-28 | Promotion tabs | RA-24 and RW-10 are split into tabs. Promotions holds the normal offers that last several days or until the stock runs out, daily offers included. Flash Sales holds isFlashSale offers with their countdown. The third tab, Offres exclusives, is V2 (row below) | — | — | — | Tab routes /promotions?tab=promotions, /promotions?tab=flash | V1 · PRM-07 |
The client gives each group a colour (red, orange, green, blue, purple, a star for suggestions). In the apps the colours become the tones of NotificationGroup, and Akram chooses the icons in DES-23.
V2 types (loyalty engine)
| Id | Name (client) | Trigger (rule, V2) | Recipients | Channels | Category · group | Action (label → deep link) | Dependencies |
|---|---|---|---|---|---|---|---|
| SN-05 | Double Points | A loyalty campaign with a ×2 multiplier starts (LOY-01 bonus campaigns, BO-53), for one day or a period | Audience of the campaign | IN_APP · PUSH | PROMOTIONAL · LOYALTY | « Commander maintenant » → /catalog | SRV-30 |
| SN-06 | Nouveau Niveau | loyalty.recomputeLevels moves the reseller up a level (Bronze → Silver → Gold → VIP, LOY-03) | The reseller | IN_APP · PUSH | TRANSACTIONAL · LOYALTY | « Découvrir mes avantages » → RA-38 /loyalty | SRV-30 |
| SN-07 | Mission Disponible | A mission is assigned. Kinds from the document: commercial (first order of the month +200 points, 5 orders +500, more than 5 000 000 DA of purchases +700, a first-time product, 3 different categories), interaction (rate the last order +50, enable notifications), challenge (Challenge de la semaine: 3 orders in 7 days; Flash Challenge: buy the chosen product today) and surprise (one random mission a week, e.g. order 10 cables) — LOY-06 | The reseller | IN_APP · PUSH | PROMOTIONAL · LOYALTY | « Voir la mission » → /missions/{missionId} (V2 screen to design) | SRV-30, DES-30 |
| SN-08 | Mission Terminée | The mission's condition is met and its points are credited | The reseller | IN_APP · PUSH | TRANSACTIONAL · LOYALTY | « Voir mon solde » → RA-38 /loyalty | SRV-30 |
| SN-09 | Cadeau Disponible | A reward becomes claimable (level reward, mission prize, Top 3 voucher, LOY-04) | The reseller | IN_APP · PUSH | TRANSACTIONAL · LOYALTY | « Récupérer mon cadeau » → RA-39 /loyalty/rewards | SRV-30 |
| SN-15 | Anniversaire d'inscription | Daily job: today is the anniversary of the account's validation date; a bonus of 300 points (setting) is credited | The reseller | IN_APP · PUSH | PROMOTIONAL · LOYALTY | « Voir mon cadeau » → RA-38 /loyalty | SRV-30 |
| SN-16 | Objectif Presque Atteint | Purchases over the level period are within loyalty.almostThresholdAmount (example: 1 000 000 DA) of the next level, sent once per period and level | The reseller | IN_APP · PUSH | PROMOTIONAL · LOYALTY | « Commencer une commande » → /catalog | SRV-30 |
| SN-22 | Notification Personnalisée (missions personnalisées) | A mission generated from the reseller's own history: « 20 chargeurs de plus cette semaine = 500 points » for a heavy charger buyer, « votre première montre connectée = 300 points » for a reseller who never bought one. Rule-based on category history in V2 | The reseller | IN_APP · PUSH | PROMOTIONAL · LOYALTY | « Relever le défi » → /missions/{missionId} | SRV-30, LOY-06 |
| SN-24 | Challenge du Mois | The monthly challenge opens, for example 5 000 000 DA of purchases this month for 1 000 extra points; progress reminders follow the caps | Audience of the challenge | IN_APP · PUSH | PROMOTIONAL · LOYALTY | « Voir le challenge » → /missions/{missionId} | SRV-30 |
| SN-27 | Top 3 Revendeurs du Mois | On the 1st of the month, the previous month's ranking is published. A weighted score combines purchase volume, number of orders and activity in the app (D-42). Prizes: 1st, a 20 000 DA voucher, the badge « Meilleur Revendeur » and a month on the home page; 2nd, 10 000 DA and « Top Revendeur »; 3rd, 5 000 DA and « Top 3 Revendeur » (LOY-07) | Winners; a home-page highlight for everyone | IN_APP · PUSH (winners) | TRANSACTIONAL · LOYALTY | « Voir le classement » → /loyalty/leaderboard | SRV-30, DES-30 |
| SN-28 (V2) | Offres Exclusives tab | Promotions whose audience is restricted to loyalty levels (Gold, VIP, …), the V2 criterion of PRM-02 | Resellers of those levels | — | PROMOTIONAL · PROMOTIONS | Tab /promotions?tab=exclusive | PRM-08, SRV-30 |
Later / to decide
| Id | Name (client) | What it needs | Decision |
|---|---|---|---|
| SN-10 | HOCO Academy (new video) | A learning module: video hosting or embedding, lessons, progress, an Academy section in both reseller apps, and back-office authoring | D-40 |
| SN-11 | Quiz | Quizzes with questions, scoring and points (needs Academy and loyalty) | D-40 |
| SN-13 | Suggestions IA (« les revendeurs qui ont acheté un Power Bank ont aussi acheté un Chargeur 65W ») | Co-purchase statistics over enough orders, in V2 advanced analytics (ANA-06); until then SN-14 covers the need with configured pairs | D-41 |
| SN-07 options | Daily / Weekly / Monthly missions (« Si nn » in the document): watch a video, browse the catalogue, add a favorite, 3 orders a week, enter the Top 10 of the wilaya, buy from 5 categories | A mission cadence engine; part of the V2 loyalty policy (D-05). Video missions wait for Academy; the product-review mission needs reviews, which are not in the cahier | D-40, D-42 |
Actions of the existing notifications
The client's examples set the tone: new product → « Commander maintenant », points earned → « Voir mon solde », new level → « Découvrir mes avantages », new video → « Regarder maintenant », one million left before Silver → « Commencer une commande ». The V1 events of the matrix get these default labels. Each template can override its label in BO-58.
| Events | Action label | Deep link |
|---|---|---|
order.*, delivery.failed, assisted_order.confirmed.by_admin, assisted_order.expired | « Voir la commande » | RA-22 / RW-09 /orders/{orderId} |
assisted_order.awaiting_confirmation, assisted_order.reminder | « Confirmer la commande » | RA-23 /orders/{orderId}/confirm |
return.* | « Voir le retour » | RA-40 /returns/{returnId} |
ticket.replied, ticket.status_changed.waiting_reseller | « Répondre » | RA-34 /support/tickets/{ticketId} |
ticket.resolved.*, ticket.rejected, other ticket.* | « Voir la demande » | RA-34 |
payment.confirmed, payment.rejected | « Voir mes paiements » | RA-31 /finance/payments |
invoice.issued | « Voir la facture » | RA-30 /finance/invoices/{invoiceId} |
account.approved, account.customer_type_changed | « Voir le catalogue » | RA-12 /catalog |
account.rejected | « Compléter mon dossier » | RA-06 |
promotion.started, daily_offer.published | « Voir l'offre » | RA-25 / RA-24 |
announcement.published | Set by the author; default « Lire le message » | /messages/{announcementId} |
security.* | « Vérifier mon compte » | RA-35 |
Notification Centre and groups
| Value | UI label (fr) | Meaning |
|---|---|---|
URGENT | Urgent | Transactional and security notifications, urgent announcements. |
PROMOTIONS | Promotions | Promotions, flash sales, price drops, commercial pushes, daily offers. |
NEW_PRODUCTS | Nouveautés | New arrivals, back in stock, limited quantity, trending product, new catalogue. |
LOYALTY | Points et niveaux | V2: points, levels, missions, gifts, challenges, Top 3. |
ACADEMY | Academy | Later: HOCO Academy videos and quizzes; hidden while empty. |
SUGGESTIONS | Suggestions | Reorder reminders, complementary products, abandoned cart. |
| Group | Holds (V1) | Push opt-out (RA-35, RW-12) |
|---|---|---|
URGENT Urgent | Every TRANSACTIONAL and SECURITY reseller notification (orders, assisted orders, returns, claims, payments, invoices, account), plus announcements ticked « Urgent » | Locked on (« Indispensable au suivi de vos commandes ») |
PROMOTIONS Promotions | SN-04, SN-18, SN-21, SN-23, daily_offer.published, non-urgent announcements | Yes |
NEW_PRODUCTS Nouveautés | SN-01, SN-02, SN-03, SN-17, SN-19 | Yes |
LOYALTY Points et niveaux | V2: SN-05 to SN-09, SN-15, SN-16, SN-22, SN-24, SN-27 | Yes (V2) |
ACADEMY Academy | Later: SN-10, SN-11; the section is hidden while empty | Yes (later) |
SUGGESTIONS Suggestions | SN-12, SN-14, SN-20; later SN-13 | Yes |
Rules:
- Home section (RA-09, RW-02): a card « Centre de notifications » under the attention slot. It shows one chip per visible group with its unread count, ordered Urgent, Promotions, Nouveautés, Suggestions (V2 adds Points et niveaux; Academy comes later), and the 3 latest unread items with their action buttons. With nothing unread it shows « Vous êtes à jour » and the 3 latest items. A chip opens the inbox filtered on that group.
- Inbox (RA-26, RW-11): the filter chips become the group tabs: « Toutes », then the groups. The « Non lues » toggle stays.
- Pop-ups: smart notifications never open a modal. In the foreground, a push appears as the usual in-app banner (realtime), and only for the
URGENTgroup. Other groups only update the badge and the home section. - Groups apply to resellers only. Delegate and staff notifications have no group.
- A notification's group is fixed by its template, never by the client app. A template that has no group defaults to
URGENTforTRANSACTIONALandSECURITYand toPROMOTIONSotherwise.
Anti-fatigue rules
Proposal to validate with HOCO (D-39, defaulted). Without limits, the 24 types could send a reseller several pushes a day. The client's own concern (« ما يحسش التطبيق يزعجو », the app must not feel like it harasses him) is the reason for these rules (NOT-17).
- Caps on promotional pushes. At most 1 push per reseller per day and 3 per rolling 7 days for the
PROMOTIONALcategory. The settings arenotifications.promotionalDailyCap(exists, 1) andnotifications.promotionalWeeklyCap(new, 3).TRANSACTIONALandSECURITYare never capped and do not count. - Capped means inbox only. A notification over the cap still writes its inbox row; it shows in the Notification Centre and in the badge. Only the push is dropped. Nothing is lost.
- Priority for the day's push. When several promotional notifications compete for a reseller's slot within the same dispatch window, the push goes to the highest of: SN-18 flash sale → SN-02 back in stock → SN-20 abandoned cart → SN-23 commercial push → SN-21 price drop → SN-03 low stock → SN-04 promotion → SN-12 reorder → SN-14 complement → SN-01 new arrival → SN-17 trending → SN-19 catalogue. The others go to the inbox only. A commercial push counts like any other: the back-office cannot exceed the caps, but BO-57 shows the split before sending.
- Quiet hours as already documented:
PROMOTIONALpushes only between 09:00 and 20:00, never on Friday before 14:00, and the Ramadan profile (quiet hours). A deferred push that would arrive after its TTL is dropped, for example a flash sale that has ended. - Merge of similar events. Events of the same type for the same reseller within 24 h become one notification with a count: « 3 nouveaux produits chez HOCO », « 2 produits de retour en stock ». The digest jobs batch arrivals and complements. The same product does not notify the same reseller twice in 7 days, whatever the type (back in stock, low stock, price drop, trending, complement).
- Opt-out per group for the non-transactional groups (Promotions, Nouveautés, Suggestions; later Points et niveaux and Academy). The reseller sets it on RA-35 and RW-12, and it applies to push only, like every preference (NOT-06). The
URGENTgroup is locked on. Turning off the category Offres et promotions turns off every promotional group at once. - Back-off (proposal): after 5 promotional pushes in a row that were not opened, the reseller's weekly cap drops to 1 for 30 days. The first opened push restores it.
Data and API impact
Additive changes only: no V1 operation is renamed and no field is removed. They are made in SRV-39 (contract and schema) and used by SRV-40.
| Where | Change |
|---|---|
Enum NotificationGroup (new) | URGENT, PROMOTIONS, NEW_PRODUCTS, LOYALTY, ACADEMY, SUGGESTIONS, with French labels and tones in enums.json |
Enum AnnouncementKind (new) | MESSAGE (the existing announcements), COMMERCIAL_PUSH (SN-23), NEW_CATALOGUE (SN-19) |
Notification | group NotificationGroup? (null for delegates and staff), actionLabel String?, actionRoute String? (the route already in data.route moves here; data.route is kept for compatibility) · index (userId, group, createdAt) |
NotificationTemplate | group NotificationGroup?, actionLabel per locale (fr required, ar and en fall back) |
NotificationRule | priority Int (rank of rule 3 above), mergeWindowHours (rule 5) |
NotificationPreference | Optional group NotificationGroup?: a row with a group mutes push for that group, and a row without a group keeps the current category × channel meaning. URGENT rows are refused with 422 PREFERENCE_NOT_EDITABLE |
Promotion | isFlashSale Boolean @default(false). Validation: when true, endsAt − startsAt is between 2 h and 48 h (400 VALIDATION_FAILED, field code FLASH_SALE_DURATION); a flash sale cannot also be a daily offer |
ProductComplement (new model, catalog) | productId, complementProductId, position, createdById, unique (productId, complementProductId), at most 5 per product, no self-reference |
Product | announceAsNew Boolean @default(true) (BO-28 box), publishedAt DateTime? (first publication; set once, never reset) |
Announcement | kind AnnouncementKind @default(MESSAGE), group NotificationGroup?, productId?, promotionId?, categoryId?, brandId?, fileId? (catalogue PDF), actionLabel? |
notifications.list | Items gain group and action: { label, deepLink } | null; new query ?group= |
notifications.unreadCount | Adds byGroup (count per NotificationGroup) for the home section |
promotions.list | Items gain isFlashSale; new query ?tab=promotions|flash (V2 exclusive). catalog.home adds flashSales[] (at most 3, with endsAt) next to dailyOffer |
notifications.preferences.get / .update | Accept and return per-group push toggles |
| Admin | admin.promotions.crud accepts isFlashSale; the admin product write payload accepts complementProductIds[] and announceAsNew; admin.announcements.crud / .send accept kind, the target and actionLabel and return the push / inbox-only split |
| Push payload | data.actionLabel and data.group are added next to route; the Android channel_id follows the category as today |
| Events | The new event keys of the matrix; no SSE event is added: notification.created carries group so the open home updates its counts |
No operation id is added to endpoints.json: every change extends an existing operation.
French UI copy
The apps are French-first. The table gives the French copy (fr, seed of NotificationTemplate) and keeps the client's own Arabic wording as the ar variant. The client's samples start with an emoji (a parcel, a flame, an hourglass, a party popper…); whether pushes keep a leading emoji is decided in DQA-10. The copy below leaves them out. The copy rules apply: title ≤ 40 characters, body ≤ 120, vous, no stock quantity.
| Id · template | Title (fr) | Body (fr) | Action (fr) | ar (client wording) |
|---|---|---|---|---|
SN-01 product.arrived | Nouveauté chez HOCO | {{productName}} vient d'arriver. Découvrez-le avant qu'il ne parte. | Commander maintenant | وصل منتج جديد عند HOCO. اكتشفه الآن قبل نفاد الكمية. |
SN-01 product.arrived.grouped | {{count}} nouveautés chez HOCO | Dont {{productName}}. Découvrez-les avant qu'elles ne partent. | Voir les nouveautés | وصلت منتجات جديدة عند HOCO. اكتشفها الآن قبل نفاد الكمية. |
SN-02 variant.restocked | De retour en stock | {{productName}}, que vous attendiez, est de nouveau disponible. | Commander maintenant | المنتج اللي كنت تستناه رجع للمخزن. |
SN-03 variant.low_stock_reached | Quantité limitée | {{productName}} : la quantité disponible est limitée. Commandez avant la rupture. | Commander maintenant | الكمية المتوفرة قليلة، اطلب الآن قبل نفاد المخزون. |
SN-04 promotion.started | Nouvelle offre | Profitez d'une remise spéciale sur {{promotionLabel}}, jusqu'à la fin de l'offre ou épuisement. | Voir l'offre | عرض جديد. استفد من تخفيض خاص على {{promotionLabel}}. العرض ساري حتى نهاية الحملة أو نفاد الكمية. |
SN-05 loyalty.double_points_started (V2) | Points doublés aujourd'hui | Aujourd'hui seulement, tous vos achats rapportent deux fois plus de points. | Commander maintenant | اليوم فقط. كل مشترياتك تمنحك ضعف النقاط. |
SN-06 loyalty.level_reached (V2) | Félicitations ! | Vous êtes maintenant {{levelLabel}}. Découvrez vos nouveaux avantages. | Découvrir mes avantages | مبروك. أصبحت {{levelLabel}}. اكتشف امتيازاتك الجديدة. |
SN-07 mission.assigned (V2) | Nouvelle mission | {{missionLabel}} : terminez-la et gagnez {{points}} points bonus. | Voir la mission | عندك مهمة جديدة. أكملها واربح Bonus Points. |
SN-08 mission.completed (V2) | Bravo ! | Mission accomplie : vous gagnez {{points}} points. | Voir mon solde | أحسنت. ربحت {{points}} نقطة. |
SN-09 reward.unlocked (V2) | Un cadeau vous attend | Vous avez un nouveau cadeau, à récupérer dès maintenant. | Récupérer mon cadeau | عندك هدية جديدة. يمكنك استلامها الآن. |
SN-10 academy.video_published (later) | Nouvelle leçon HOCO Academy | {{lessonTitle}} est disponible. | Regarder maintenant | درس جديد متوفر. |
SN-11 academy.quiz_published (later) | Quiz disponible | Répondez au quiz et gagnez des points supplémentaires. | Répondre au quiz | جاوب على الاختبار واربح نقاط إضافية. |
SN-12 reorder.reminder_due | Besoin de réassort ? | Vous commandez souvent des {{categoryName}}. Voulez-vous recommander ? | Commander à nouveau | لاحظنا أنك عادة تطلب {{categoryName}}. هل تريد إعادة الطلب؟ |
SN-13 suggestion.bought_together (later) | Souvent achetés ensemble | Les revendeurs qui ont acheté {{productName}} ont aussi acheté {{otherProductName}}. | Voir le produit | التجار اللي شراو {{productName}} شراو أيضًا {{otherProductName}}. |
SN-14 complement.suggested | Pensez au complément | Avec {{productName}}, avez-vous aussi besoin de {{complementName}} ? | Voir le produit | هل تحتاج أيضًا إلى {{complementName}}؟ |
SN-15 loyalty.anniversary_reached (V2) | Joyeux anniversaire HOCO ! | {{years}} an(s) avec nous : {{points}} points offerts. | Voir mon cadeau | عيد سعيد. هدية {{points}} نقطة. |
SN-16 loyalty.level_almost_reached (V2) | Plus que {{remainingAmount}} | Il ne vous reste que {{remainingAmount}} d'achats pour passer {{nextLevelLabel}}. | Commencer une commande | بقي لك {{remainingAmount}} فقط للوصول إلى {{nextLevelLabel}}. |
SN-17 trending.computed | Le plus vendu de la semaine | {{productName}} est le produit le plus commandé cette semaine. | Voir le produit | أكثر منتج مبيعًا هذا الأسبوع. |
SN-18 flash_sale.started | Vente flash | Remise exceptionnelle sur {{productName}}. Plus que {{remaining}} : commandez avant la fin. | Commander maintenant | Flash Sale. خصم استثنائي على {{productName}}. باقي {{remaining}} فقط. اطلب الآن قبل انتهاء العرض. |
SN-19 catalogue.published | Nouveau catalogue HOCO | Le catalogue {{catalogueTitle}} est disponible. | Voir le catalogue | نزلت نسخة جديدة من الكاتالوغ. |
SN-20 cart.abandoned | Votre panier vous attend | Vous avez oublié {{itemCount}} articles dans votre panier. | Finaliser ma commande | نسيت منتجات في السلة. |
SN-21 price.dropped | Baisse de prix | Le prix de {{productName}}, qui vous intéresse, a baissé. | Voir le produit | المنتج اللي مهتم بيه نقص سعره. |
SN-22 mission.personalised (V2) | Un défi pour vous | Cette semaine, {{missionLabel}} et gagnez {{points}} points. | Relever le défi | هذا الأسبوع، إذا طلبت 20 Chargeur إضافي تربح 500 نقطة. |
SN-23 commercial_push.sent | Written by the author (default: {{productName}}) | Written by the author, ≤ 120 characters | Commander maintenant (editable) | Written by the author |
SN-24 challenge.started (V2) | Challenge du mois | Atteignez {{targetAmount}} d'achats ce mois-ci et gagnez {{points}} points en plus. | Voir le challenge | إذا وصلت إلى {{targetAmount}} هذا الشهر، تربح {{points}} نقطة إضافية. |
SN-27 leaderboard.published (V2) | Vous êtes dans le Top 3 ! | Vous êtes {{rankLabel}} revendeur du mois : bon d'achat de {{voucherAmount}} et badge {{badgeLabel}}. | Voir le classement | المركز {{rank}}. Bon d'achat {{voucherAmount}}. |
Typical values for the length check: productName BOROFONE BX51 câble USB-C 1 m · promotionLabel Power Bank HOCO J101 · remaining 18 h · categoryName câbles · itemCount 4 · remainingAmount 1 000 000,00 DA. SN-04's client example (Power Bank at 2 100 DA instead of 2 500 DA) shows the promotional price next to the normal one on RA-25, not in the push. The push never carries a price, because prices depend on the customer type.
Plan
The V1 work is six tasks: DES-23 (Akram: Notification Centre, action buttons, promotion tabs, flash-sale countdown), SRV-39 (contract and schema), SRV-40 (triggers and jobs), DSH-14 (back-office: commercial push, new catalogue, flash-sale fields, complementary products, settings), WEB-06 (reseller web) and MRA-11 (reseller app). Their dates are on the timeline. The extra 4 days on Anis's lane move Production go-live and Pilot starts by about four working days. Both still meet their targets in the milestones table. The pilot go / no-go moves by the same amount. If that matters more than scope, NOT-15 and then NOT-11 move after go-live first (D-38).
Ambiguities in the client text
| Point | Reading applied | Confirm with HOCO |
|---|---|---|
| Content of the Urgent group | The client does not list it. The transactional and security notifications go there, plus urgent announcements | Yes, at the next Thursday review |
| « نسخة جديدة » for SN-19 (a new edition of what?) | A new edition of HOCO's catalogue (PDF or collection) published in BO-57; new products alone are SN-01 | Yes |
| SN-03 low stock without quantities | The notification says « Quantité limitée », the product page stays « En stock », and no number appears anywhere (STK-07) | Already covered by STK-07 |
| SN-12 « الذكاء الاصطناعي أو تاريخ الطلبات » (AI or order history) | Order history only in V1 (cadence rule); AI is SN-13, later | D-41 |
| SN-07 « Si nn : Daily / Weekly / Monthly » | Read as an alternative way of organising the missions, not as extra missions; decided with the V2 loyalty policy | D-42, D-05 |
| SN-07 « ادخل Top 10 في ولايتك » (enter the top 10 of your wilaya) | A ranking per wilaya, next to the national Top 3 of SN-27 (V2) | With D-42 |
| SN-22 « واربح 300 نقط » written twice | A typo; one reward of 300 points | — |
| Top 3 « النشاط داخل التطبيق » (activity in the app) | Measured from sessions and orders placed in the app; the weights are to decide | D-42 |
| Abandoned cart « بعد ساعتين » | 2 h after the last cart change, deferred by quiet hours | D-44 |
| Back-in-stock « إذا كان التاجر سبق وشراه » (if the reseller bought it before) | Ordered in the last 90 days, plus favorites and carts | D-43 |
| Flash Challenge (« اشترِ المنتج المحدد اليوم فقط », buy the chosen product today only) versus Flash Sale | The challenge is a V2 mission with points; the flash sale is a V1 promotion with a price | — |
Notifications matrix
Every event that notifies someone — trigger, recipients, channels, preference category and group, deep link, template and release, smart notifications included — with the French copy, quiet hours, grouping, retries, preferences, channel costs and the checklist for adding an event.
Acceptance scenarios
The cahier's fifteen priority acceptance scenarios and thirty-two complementary ones as executable test scripts with seed data, steps, expected results, requirements covered and evidence — then the acceptance procedure up to the signed PV de recette.