Support and reports
Page specs BO-55 to BO-60: tickets and after-sales claims, ticket detail with SAV resolution, announcements, notification templates and rules, the reports library and the export centre.
Support handles reseller tickets, including after-sales claims (SAV, ticket type AFTER_SALES). Claims are resolved in V1 by replacement, return, credit note, repair or rejection (SUP-02, SUP-04). Communication covers announcements and the notification matrix. Reports and exports give the essential indicators of cahier §4 and §1.4 in PDF, Excel and CSV (cahier §9).
| ID | Screen | Section | Template | Release | Design | Build |
|---|---|---|---|---|---|---|
BO-55 | Tickets list | Support | template | V1 | Day 19 | DSH-10 |
BO-56 | Ticket detail | Support | template | V1 | Day 19 | DSH-10 |
| ID | Screen | Section | Template | Release | Design | Build |
|---|---|---|---|---|---|---|
BO-57 | Announcements | Communication | template | V1 | Day 19 | DSH-10 |
BO-58 | Notification templates & rules | Communication | template | V1 | Day 19 | DSH-10 |
| ID | Screen | Section | Template | Release | Design | Build |
|---|---|---|---|---|---|---|
BO-59 | Reports library | Reports | bespoke | V1 | Day 19 | DSH-11 |
BO-60 | Export centre | Reports | template | V1 | Day 19 | DSH-11 |
BO-55 — Tickets list
| Field | Value |
|---|---|
| Template | List |
| Release | V1 |
| Design day | Day 19 — DES-19 |
| Build task | DSH-10 |
| Route | /support/tickets (?view=) |
| Requirements | SUP-02 · SUP-04 · SUP-01 |
| Permissions required | support.view · support.update (assign, status, priority in bulk) |
Purpose. The support queue: reseller tickets and after-sales claims, to assign, prioritise and answer in time.
Who uses it. Commercial admin, finance (billing tickets), delivery manager (delivery tickets), super admin.
Entry points. Support › Tickets et SAV (badge = unassigned open tickets), BO-11 Tickets et SAV, and BO-69 « Réclamations SAV ».
Layout.
- Tabs: « Non assignés », « Mes tickets », « SAV » (
AFTER_SALES), « Ouverts » (OPEN,IN_PROGRESS), « En attente du revendeur » (WAITING_RESELLER), « Résolus », « Rejetés », « Fermés », « Tous ».
| Column | Source field | Sortable | Default visible |
|---|---|---|---|
| N° | number (TKT-2026-000045) | Yes | Yes |
| Sujet | subject | No | Yes |
| Type | type (TicketType; SAV badge) | Yes | Yes |
| Revendeur | Store name + wilaya | Yes | Yes |
| Commande | order.number | Yes | Yes |
| Problème (SAV) | AfterSalesIssue of the claimed items | No | Yes on « SAV » |
| Statut | status (TicketStatus; staff label « En attente du revendeur » for WAITING_RESELLER) | Yes | Yes |
| Priorité | « Basse », « Normale », « Haute », « Urgente » (Assumption: no enum yet) | Yes | Yes |
| Assigné à | assignee.displayName | Yes | Yes |
| Dernier message | Time and author side (reseller / HOCO) | Yes | Yes |
| Attente | Time since the last reseller message without a reply (amber after 4 h, red after 24 h; Assumption: SLA to confirm) | Yes | Yes |
| Résolution | AfterSalesResolution | Yes | No |
| Créé le | createdAt | Yes | No |
- Filters:
q,type,status,priority,assignee(incl.none),reseller,wilaya,from/to,issue. - Default sort: Attente descending.
- Bulk actions (
admin.tickets.updateper ticket): « Assigner », « Changer la priorité », « Fermer » (resolved only).
Data. admin.tickets.list, admin.tickets.update, admin.users.list (assignee picker).
Actions. Bulk assignment is not optimistic. It is audited UPDATE per ticket and notifies the assignee (in-app).
Rules.
- A ticket created by a reseller starts
OPENand unassigned. Its first reply moves it toIN_PROGRESS. - Tickets are never deleted.
- After-sales claims carry the order and the claimed lines.
Real-time. The admin stream has no ticket event in V1. The list and badge poll every 60 s while visible (see contract notes).
States. « Aucun ticket non assigné » is a positive empty state.
Acceptance criteria.
- A ticket opened in the reseller app appears in « Non assignés » within 60 s.
- The « SAV » tab lists exactly the
AFTER_SALEStickets. - Bulk assignment notifies each assignee once.
BO-56 — Ticket detail
| Field | Value |
|---|---|
| Template | Detail (conversation with a side panel) |
| Release | V1 |
| Design day | Day 19 — DES-19 |
| Build task | DSH-10 (SAV workflow: DSH-13) |
| Route | /support/tickets/[ticketId] |
| Requirements | SUP-02 · SUP-04 · ORD-13 · FIN-08 |
| Permissions required | support.view · support.update (reply, internal note, assign, status, priority) · support.validate (resolve an after-sales claim) · finance.view (credit-note amounts) |
Purpose. Answer a reseller, keep internal notes, and, for an after-sales claim, take it from diagnosis to resolution. The resolution is one of Remplacement (a free replacement order), Retour (creates a return), Avoir (credit note), Réparation, or Refusée with a reason (§1b.9).
Who uses it. Commercial admin (claims), finance (billing), delivery manager (delivery issues).
Entry points. BO-55, BO-69 « Réclamations SAV », BO-39 Retours et SAV, BO-11, and notifications.
Layout.
- Header:
TKTnumber, subject,TicketTypeandTicketStatuspills, priority, assignee, reseller (link to BO-11, with phone and WhatsApp), related order (link to BO-39). - Main, the conversation:
- Public messages, aligned by author.
- Internal notes, on a yellow background with « Note interne — invisible pour le revendeur ».
- Attachments (
TICKET_ATTACHMENT, 10 MB max, signed URLs). - Composer with the toggle « Réponse au revendeur » / « Note interne », attachments, and « Envoyer ».
- Side panel:
- Fields Statut, Priorité, Assigné à, Type (editable with
support.update). - Reseller summary.
- History.
- Fields Statut, Priorité, Assigné à, Type (editable with
- After-sales claim panel (type
AFTER_SALES), at the top of the main column:- Claimed items (
TicketItem): product and variant, ordered quantity, claimed quantity, issue (AfterSalesIssue), photos. - Warranty status, computed from the delivery date and the product's warranty: « Sous garantie jusqu'au 03/05/2027 » or « Hors garantie depuis le 03/11/2026 ».
- Order context: delivery date, invoice, previous claims on the same order.
- The primary action « Résoudre la réclamation » (with
support.validate).
- Claimed items (
After-sales resolution
« Résoudre la réclamation » opens a dialog. The chosen resolution is sent with admin.tickets.resolve.
| Resolution | Inputs | Effect | Confirmation (FR) |
|---|---|---|---|
Remplacement (REPLACEMENT) | Quantities to replace per claimed line (≤ claimed); delivery address (reseller's default); note | Creates a free replacement order (CMD-…, lines at 0 DA, channel BACK_OFFICE) linked to the ticket. Like every order, it waits in BO-41 for confirmation, then follows preparation and shipping (ORD-14). | « Créer une commande de remplacement gratuite de 2 articles pour Boutique Nour ? Elle devra être confirmée comme toute commande. » |
Retour (RETURN) | Quantities to return per line | Creates a return RET-… (APPROVED) in BO-69. Its reception restocks automatically (defective items flagged not to restock) and issues the credit note. | « Créer un retour de 2 articles ? Le revendeur sera informé des modalités de retour. » |
Avoir (CREDIT_NOTE) | Amount (default: Σ claimed quantities × unit price TTC paid; can be lowered, not raised); comment | Issues a credit note without physical return (FIN-08), visible in BO-44 « Avoirs » | « Émettre un avoir de 8 750,00 DA TTC pour Boutique Nour ? » |
Réparation (REPAIR) | Note (required): what is repaired, expected return date | Records the repair under warranty; the ticket becomes RESOLVED | « Enregistrer la réparation sous garantie ? » |
Refusée (REJECTED) | Reason (required, shown to the reseller; chips: « Hors garantie », « Dommage dû à une mauvaise utilisation », « Article non fourni par HOCO ») | The ticket becomes REJECTED | « Refuser la réclamation ? Le motif sera communiqué au revendeur. » |
Effects shared by all resolutions:
- The ticket records the resolution, its author and the created record (order, return or credit note), linked in the claim panel.
- An automatic public message summarises the decision for the reseller: « Votre réclamation est résolue : remplacement par la commande CMD-…-201 ».
- The reseller is notified by push and in-app, live while their app is open (
ticket.replied,return.status_changedonevents.stream). - The resolution is audited (
VALIDATE, orREJECTfor a refusal).
Data. admin.tickets.get, admin.tickets.reply, admin.tickets.update, admin.tickets.resolve, files.createUpload, files.downloadUrl, admin.orders.get (order context).
Actions.
| Action | Endpoint | Behaviour | Audit | Notifies |
|---|---|---|---|---|
| « Envoyer » (reply) | admin.tickets.reply (public) | Status becomes WAITING_RESELLER unless another status is chosen in the composer | CREATE (message) | Reseller (push, in-app, live) |
| « Envoyer » (internal note) | admin.tickets.reply (internal: true) | Visible to staff only | CREATE | Mentioned staff (in-app) |
| Change status, priority or assignee | admin.tickets.update | Optimistic for priority; not for status | UPDATE / STATUS_CHANGE | Assignee; reseller on RESOLVED / CLOSED |
| « Résoudre la réclamation » | admin.tickets.resolve | See the resolution table | VALIDATE / REJECT | Reseller |
Rules.
- Internal notes are never returned by reseller operations (
tickets.getreturns public messages only). - One resolution per claim. A claim can be reopened to resolve again only by moving it back to
IN_PROGRESS; the first resolution and its records are kept. - Claimed quantities are capped by the delivered quantities of the order, minus previous claims and returns on the same lines.
- Replacement orders are never confirmed automatically. They appear in BO-41 with the badge « Remplacement SAV ».
- Out of warranty: a claim may still be resolved; the dialog shows « Hors garantie » as a warning.
Real-time. None in the admin stream. The conversation polls every 30 s while open (see contract notes).
States.
- Reseller attachments still uploading.
- A closed ticket is read-only with « Rouvrir ».
- The claim panel shows « Article déjà réclamé (TKT-…) » on a line claimed before.
Acceptance criteria.
- A claim on 2 faulty units resolved as Remplacement creates a 0 DA order of 2 units, linked to the ticket. That order waits in BO-41 until confirmed.
- Retour creates a return in BO-69. Its reception re-enters the non-defective quantities in stock and issues a credit note, with no manual stock action.
- Avoir cannot exceed the amount paid for the claimed quantities.
- Refusée requires a reason, which the reseller sees in their app.
- Internal notes never appear in the reseller app.
BO-57 — Announcements
| Field | Value |
|---|---|
| Template | List (with a composer drawer) |
| Release | V1 |
| Design day | Day 19 — DES-19 |
| Build task | DSH-10 |
| Route | /communication/announcements |
| Requirements | NOT-07 · NOT-06 |
| Permissions required | communication.view · communication.create · communication.update · communication.delete (drafts) · communication.validate (send) |
Purpose. Send messages from the back-office to delegates or resellers by target: the « Messages » of the delegate app (cahier §6.1) and announcements in the reseller app.
Who uses it. Commercial admin.
Entry points. Support › Annonces.
Layout.
- Table: Titre, Public (delegates / resellers), Ciblage summary, Canaux, État (« Brouillon », « Programmée », « Envoyée »), Envoyée le, Lus (« 812 / 1 245 · 65 % »).
- Composer drawer:
- Titre: required, 80 characters max.
- Message: required, plain text with links, 1 000 characters max.
- Public: « Délégués » or « Revendeurs ».
- Ciblage:
- delegates: all, zones, or specific delegates;
- resellers: all, wilayas, segments, customer types, or specific resellers.
- Notification push: toggle, on by default.
- Envoi: « Maintenant » or a date and time.
- The audience count is shown live: « 1 245 destinataires ».
- Preview in a phone frame.
Commercial push and new catalogue (change request 03). NOT-16, NOT-11, DSH-14.
- The composer gets a Type selector (
AnnouncementKind): « Message » (as above), « Push commercial », « Nouveau catalogue ». The last two are for resellers only. - Push commercial: target picker (product, promotion, category or brand), title ≤ 40 characters and message ≤ 120, action label (default « Commander maintenant »), and an extra audience criterion « Acheteurs de la catégorie … sur les N derniers jours ». Before sending, the count reads « 1 245 destinataires · 1 010 en push · 235 dans la boîte seulement (plafond atteint) ».
- Nouveau catalogue: PDF upload (
CATALOG_PDF), cover image, optional category or brand to open, action « Voir le catalogue ». - Both kinds are category
PROMOTIONAL, group Promotions or Nouveautés, and count in the caps (NOT-17). A Message can be given a group, Urgent when the « Urgent » box is ticked.
Data. admin.announcements.crud, admin.announcements.send.
Actions. « Envoyer » (communication.validate): « Envoyer cette annonce à 1 245 revendeurs ? Une notification push sera envoyée. ». Not optimistic, audited CREATE / STATUS_CHANGE. A sent announcement cannot be edited.
Rules.
- Announcements belong to the
ANNOUNCEMENTcategory.- The inbox always receives them.
- Push respects the recipient's preference (NOT-06).
- Read counts come from
AnnouncementRead.
Real-time. None.
States. A scheduled announcement shows its countdown. A send failure lists the failed deliveries (link to BO-58 Journal).
Acceptance criteria.
- An announcement to the delegates of one zone reaches only them: their app inbox shows it, and nobody else's does.
- The read rate updates as recipients open it.
- A sent announcement is read-only.
BO-58 — Notification templates & rules
| Field | Value |
|---|---|
| Template | Settings |
| Release | V1 |
| Design day | Day 19 — DES-19 |
| Build task | DSH-10 |
| Route | /communication/notifications (?tab=rules, templates or log) |
| Requirements | NOT-04 · NOT-05 · ORD-15 |
| Permissions required | communication.administer (rules, templates) · communication.view (log) |
Purpose.
- Configure which event goes through which channel to whom (cahier §8 « Push, in-app, WhatsApp, SMS ou email selon le type d'événement »).
- Edit the localised templates.
- Check the delivery log.
Who uses it. Super admin, commercial admin.
Entry points. Support › Notifications.
Layout.
- Tab « Règles »: a matrix with one row per event and columns
IN_APP,PUSH,SMS,EMAIL,WHATSAPP(V1: share links only) per recipient (reseller, delegate, assigned staff, role).- Example events: order received, order confirmed, order on hold, order refused, order modified, order shipped, order delivered, assisted order to confirm, account validated or rejected, task assigned, ticket reply, claim resolved, return decided or received, payment confirmed or rejected, credit note issued.
- Locked cells (lock icon): transactional and security channels that cannot be disabled. For example, every order status change notifies the reseller by push and in-app (ORD-15).
- Tab « Modèles »: per event × channel × locale (FR; AR and EN prepared).
- Titre (push), Objet (email) and Message.
- Variables listed on the right and inserted as
{{order.number}},{{reseller.storeName}},{{order.totalTtc}}. - A preview with sample data.
- For SMS, a segment counter (160 GSM-7 / 70 UCS-2 characters per segment).
- Tab « Journal »: date, event, channel, recipient, status (sent / failed), error message. Filters
channel,status,from/to,recipient.
Smart notifications (change request 03). NOT-10, NOT-17, DSH-14.
- Règles adds the smart events of the matrix, each with its group, its priority rank and an on/off switch per event.
- Modèles adds the Bouton d'action field (label per locale, required for reseller events) next to Titre, and shows the group.
- A new tab, « Notifications intelligentes », holds the settings: caps per day and per week, back-in-stock look-back (90 days), minimum out-of-stock time (24 h), abandoned-cart delay (2 h), price-drop minimum (5 %), reorder grace (1 day), and the times of the digest jobs. Every change is audited
UPDATE.
Data. admin.notifications.rules, admin.notifications.templates, admin.notifications.log.
Actions.
- Save the rules (one PUT of the matrix): « Enregistrer les règles ? Les prochains envois suivront cette configuration. ».
- Save a template, per template.
- Both are audited
UPDATE.
Rules.
- A template with an unknown variable cannot be saved.
- Transactional notifications (category
TRANSACTIONAL) and security ones cannot be switched off for the reseller (NotificationCategory). - The notifications matrix holds the seeded configuration.
Real-time. None.
States. The log is empty until the first sends. A failed SMS shows the provider error.
Acceptance criteria.
- Disabling SMS for « commande expédiée » stops SMS for that event while push and in-app continue.
- Cells for order status changes to the reseller cannot be disabled.
- A template using
{{order.unknown}}is refused with the variable named.
BO-59 — Reports library
| Field | Value |
|---|---|
| Template | Bespoke (Dashboard skeleton: catalogue + report runner) |
| Release | V1 |
| Design day | Day 19 — DES-19 |
| Build task | DSH-11 |
| Route | /reports · /reports/[reportKey] (filters in the URL) |
| Requirements | ANA-03 · ANA-04 · ANA-05 · ORD-09 |
| Permissions required | reports.view (each report also needs its module's view permission) · reports.export (export) |
Purpose. The essential reports (cahier §4 « Indicateurs et rapports »):
- revenue by period, zone, delegate, reseller, brand and product;
- prospect conversion and first orders;
- stock-outs and slow movers;
- pending, late, cancelled and returned orders.
It also carries the success KPIs of cahier §1.4 (ANA-04).
Who uses it. Direction, commercial admin, finance, stock.
Entry points. Rapports › Rapports, and drill-downs from the dashboards (BO-04, BO-05).
Layout.
- Catalogue: cards grouped by theme. Each card shows the title, a one-line definition and « Ouvrir ». Only the reports the user may run are listed (
admin.reports.list). - Runner:
- The filter bar (each report declares its filters: period, wilaya, commune, delegate, reseller, customer type, brand, category, product, channel), synced to the URL.
- Regrouper par (when the report allows it), « Exécuter », « Exporter ».
- A summary strip with the totals.
- A chart and a paginated table, with a totals row.
- « Définition » expands the exact formula.
Report (reportKey) | Groups | Definition | Needs |
|---|---|---|---|
CA par période (sales-by-period) | Day / week / month | Σ net HT of counted orders by validation date (BO-04 basis) | orders.view |
CA par zone (sales-by-zone) | Zone, wilaya, commune | Same, by delivery address | orders.view |
CA par délégué (sales-by-delegate) | Delegate | Same, by attributed delegate | orders.view + field.view |
CA par revendeur (sales-by-reseller) | Reseller (+ customer type) | Same; with order count, average basket, last order | orders.view + crm.view |
CA par marque / par produit (sales-by-brand, sales-by-product) | Brand, category, product, variant | Line net HT and quantities | orders.view |
CA par type de client (sales-by-customer-type) | CustomerType | Same; share of revenue per type | orders.view |
Conversion terrain (field-conversion) | Delegate, zone, month of creation | Prospects created → accounts created → first orders (cohort) | field.view + crm.view |
Premières commandes (first-orders) | Delegate, channel | First orders with the reseller and source delegate (ORD-09) | orders.view |
Ruptures (stock-outs) | Variant, brand | Variants out of stock, days out of stock in the period, 30-day sales lost estimate | stock.view |
Faible rotation (slow-movers) | Variant | Physical stock above 0 and no shipment for N days (default 60) | stock.view |
Commandes en attente de confirmation (orders-to-confirm) | Channel, day | Orders SUBMITTED / PENDING with age, and confirmation delays (median, 90th percentile) | orders.view |
Commandes en retard (orders-late) | Status, wilaya | Confirmed orders not shipped within 48 h (setting) | orders.view |
Annulations et refus (orders-cancelled) | Reason, channel | Cancelled and refused orders with their reasons | orders.view |
Retours et SAV (returns) | Reason, product, resolution | Returns and claims, quantities, credit notes | orders.view + support.view |
KPI de succès (success-kpis) | Month | Adoption (accounts activated ÷ invited, active users), field conversion, digitalisation (share of orders via app and web), tour performance (visits done ÷ planned), loyalty (order frequency; levels in V2), operational quality (cancellations, refusals, late orders, returns) — cahier §1.4 | reports.view + the modules involved |
Data. admin.reports.list, admin.reports.run (filters, page, pageSize → rows and totals), admin.exports.create.
Actions. « Exporter » (PDF with filters and chart, XLSX or CSV of all rows) creates an async export and shows the toast with the link to BO-60. It is audited EXPORT.
Rules.
- One set of definitions: the same as the dashboards (BO-04). A report total with the same filters equals the card.
- Permission-filtered at row level (financial reports need
finance.view). Purchase-price margins appear only withpricing.view. - Time zone: periods are business days in
Africa/Algiers.
Real-time. None. Reports run on demand.
States.
- Long reports: when the response takes over 3 s, a skeleton with « Calcul en cours… » shows.
- No data: « Aucune donnée pour ces filtres ».
- Not permitted (from an old link): « Accès refusé ».
Acceptance criteria.
- CA par période by month for this year equals CA de l'année on BO-04 with the same filters.
- Conversion terrain per delegate equals the delegate's figures in BO-17 for the same period.
- The export of a report contains the same rows and totals as the screen.
- A stock manager without
orders.viewdoes not see the revenue reports in the catalogue.
BO-60 — Export centre
| Field | Value |
|---|---|
| Template | List |
| Release | V1 |
| Design day | Day 19 — DES-19 |
| Build task | DSH-11 |
| Route | /exports |
| Requirements | ANA-05 · AUD-01 |
| Permissions required | reports.export |
Purpose. Collect every export the user requested (lists and reports, PDF / XLSX / CSV, cahier §9) and download it once ready.
Who uses it. Every role that exports.
Entry points. Rapports › Exports (badge = running exports), and the export toasts.
Layout.
| Column | Source field | Sortable | Default visible |
|---|---|---|---|
| Export | Source (« Commandes », « CA par zone ») + filters summary | No | Yes |
| Format | ExportFormat | Yes | Yes |
| Demandé le | createdAt | Yes (default descending) | Yes |
| Statut | JobStatus | Yes | Yes |
| Lignes | rowCount | Yes | Yes |
| Taille | size | Yes | No |
| Expire le | expiresAt | Yes | Yes |
Row actions: « Télécharger » (when SUCCEEDED), « Relancer » (same parameters), « Voir les filtres ».
Data. admin.exports.list, admin.exports.get (signed download URL, valid 5 minutes), admin.exports.create.
Actions. « Télécharger » fetches a fresh signed URL and starts the download. « Relancer » creates a new job. The audit is written at creation (EXPORT, with source and filters).
Rules.
- Users see only their own exports.
- Files (
GENERATED_DOCUMENT, private) expire after 7 days. Assumption — the retention is to confirm. They then showEXPIRED. - An export contains only what the user was allowed to see when it was requested.
Real-time. No export event. While any job is QUEUED or RUNNING, the page and the badge poll every 5 s. Completion shows the toast « Export prêt — Télécharger ».
States. « Aucun export » appears on first use. A FAILED job shows its error with « Relancer ».
Acceptance criteria.
- An export requested from BO-38 appears here at once as
QUEUED, thenSUCCEEDEDwith its row count, and downloads through a short-lived URL. - Another user's exports are never listed.
- After expiry, the download is no longer possible and « Relancer » is offered.
Promotions and loyalty
Page specs BO-49 to BO-54: promotions list, promotion editor with targeting, stacking and preview, banners and daily offers, and the V2 packs, loyalty and rewards pages.
Administration
Page specs BO-61 to BO-68 and BO-70: users, the roles and permissions matrix, activity log, business settings, reference lists, app versions, data imports, my profile and sessions, and support regions with their WhatsApp numbers.