Audit trail & history
The append-only activity journal of sensitive actions, the business histories kept on orders, stock, prices and resellers, and the back-office viewer.
This area makes every critical action traceable "with user, date, time and context" (cahier §2.1, §3.1, §4.3, §4.4, §8, §10). It has two layers. The activity journal (AuditLog) records who did what, from which app and address — written by the server's audit module for every module. The business histories (order status changes and modifications, stock movements, price changes, reseller status and assignment changes, credit-limit and tour status changes) are structured tables written by each domain module and shown where the record is viewed. The journal is read in the back-office (BO-63); histories appear in the back-office, and the parts that concern them in the reseller apps (RA, RW).
| ID | Requirement | Release | Priority | Source | Apps |
|---|---|---|---|---|---|
AUD-01 | Activity journal: logins, creations, modifications, validations, exports, deletions with user, time and context | V1 | MUST | §3.1, §10 | API · BO |
AUD-02 | Entity histories: order changes, status changes, stock movements and price changes are kept and viewable in context | V1 | MUST | §4.3, §4.4, §8 | API · BO |
AUD-03 | Audit log viewer with filters and export for authorised users | V1 | SHOULD | §10 | BO |
Requirements
AUD-01 — Activity journal
Statement — The system shall record in an append-only activity journal every sign-in, creation, modification, status change, validation, refusal, export, import, permission change, override and deletion, with the actor, the time and the context of the action.
Rules
- Journaled: every successful mutating operation on a business record (
CREATE,UPDATE,DELETE,STATUS_CHANGE,VALIDATE,REJECT); sign-ins (LOGIN,LOGIN_FAILED,LOGOUT); exports (EXPORTwith the list or report, the filters and the row count); imports (IMPORTwith the file, counts and mode); role and permission changes (PERMISSION_CHANGE); overrides of a business control (OVERRIDEwith the control and the reason); actions of the system itself (actorSYSTEM: automatic statuses, expiries, scheduled jobs). - Reads are not journaled, with two exceptions: issuing a download URL for a private store document (ID card, RC, NIF…) and every export.
- Each entry stores:
occurredAt(server time, plus the device time for offline actions), the actor (user id, user type and roles at that moment, orSYSTEM), the action (AuditAction), the entity type, id and business number (CMD-2026-000158), the changed fields with before and after values (only the fields that changed), the reason when the operation requires one, and the context: client (ClientApp), app version, IP, user agent or device id, session id, request id and operation id (admin.orders.validate). - Never written: passwords, one-time codes, tokens, file contents. Financial values are written — the journal itself is restricted to
audit.view. - The entry is inserted in the same database transaction as the change: no change without an entry, no entry for a change that was rolled back. Sign-in failures are written outside business transactions.
- Append-only: no operation updates or deletes entries, and the application's database role has only
INSERTandSELECTon the journal table. - Offline actions replayed through
sync.batchare journaled once, with the device time and the reception time andClientApp = DELEGATE_APP; an idempotent replay (REPLAYED) adds nothing. - Not journaled because they are data, not actions: location pings, notification deliveries, cart edits (the order created at checkout is journaled).
- Retention follows the policy validated with HOCO under Law 18-07 (SEC-08); the proposed default is 24 months online, then archived.
| Value | UI label (fr) | Meaning |
|---|---|---|
LOGIN | Connexion | |
LOGIN_FAILED | Échec de connexion | |
LOGOUT | Déconnexion | |
CREATE | Création | |
UPDATE | Modification | |
DELETE | Suppression | |
STATUS_CHANGE | Changement de statut | |
VALIDATE | Validation | |
REJECT | Refus | |
EXPORT | Export | |
IMPORT | Import | |
PERMISSION_CHANGE | Changement de droits | |
OVERRIDE | Dérogation |
Acceptance criteria
- Validating order
CMD-2026-000158creates oneVALIDATEentry with the actor, their roles, appDASHBOARD, IP, request id and the order number. - Changing a reseller's main phone creates an
UPDATEentry whose changes contain the old and new phone. - A validation refused with
422 STOCK_INSUFFICIENTcreates no entry; the same validation with a stock override createsVALIDATEandOVERRIDEentries with the reason. - A visit note recorded offline and replayed creates one entry carrying both times; replaying the same
Idempotency-Keyadds no entry. UPDATE audit_logs …run with the application's database role fails with a permission error.- The entries of a password reset contain neither the password nor the code.
- Opening a reseller's ID card from the back-office creates an entry naming the document.
Data — AuditLog (partitioned by month), Session (context).
Interfaces
- Screens: BO-63 Activity log
- API:
admin.audit.listGET /admin/audit-logs
Notes / open points — The retention duration is one of the data-retention decisions listed in cahier §15 (see the decision register).
AUD-02 — Business histories kept and shown in context
| Release | Priority | Source | Apps | Owner tasks |
|---|---|---|---|---|
| V1 | MUST | cahier §4.3, §4.4, §8 | API · BO | SRV-02 |
Statement — The system shall keep a structured, never-edited history of order statuses and modifications, stock movements, price changes and the other lifecycle changes listed below, and shall show each history where the record is viewed.
Rules
-
Histories, when they are written and where they are shown:
History Model Written on Shown in Order status OrderStatusChange(from, to, time, actor, reason, client)every transition, including automatic ones RA-22, RW-09, BO-39 Order modifications OrderChange(line or field, before, after, reason, actor)admin.orders.modify, address or payment-method changeBO-39; a summary to the reseller Stock StockMovement(type, quantities, balance after, reference, actor)every change of physical or reserved stock BO-34, product editor Prices PriceChange(variant, field —priceSuperGros,priceDemiGros,priceDetail,purchasePrice,recommendedPrice,vatRate— old, new, source, actor)product editor, imports BO-28 (price history) Reseller status ResellerStatusChangeevery lifecycle change, manual or automatic BO-11 Reseller assignment ResellerAssignment(delegate, zone, from, to, reason)every assignment BO-11 Customer type type history of the reseller (from, to, time, actor, reason) declaration, confirmation at validation, back-office change BO-11 Returns status history of ReturnRequest, reception quantities, credit noteevery return transition BO-69, RA-40 Reseller profile fields AuditLogUPDATEentries of the resellerprofile.update,admin.resellers.update, account claimBO-11 Historique tab Credit limit CreditLimitChange(old, new, blocked, reason)admin.credit.updateBO-46 Tour status TourStatusChangeevery tour transition BO-23 -
Rows are written in the same transaction as the change and never updated or deleted; a correction is a new row.
-
Each row stores the actor (user id, or
SYSTEM) and the time. The back-office shows « Système » for automatic changes; the reseller apps show « HOCO » instead of staff names. -
Times are displayed in
Africa/Algiers: « 14 mai 2026 à 10:32 ». -
Histories are business records kept for the life of the record, independently of the journal's retention; archiving a product or disabling a user keeps them.
Acceptance criteria
- After an order goes
SUBMITTED → VALIDATED → PREPARING,admin.orders.historyreturns three status rows in order with actors, and the reseller'sorders.gettimeline shows the same three steps with « HOCO » as actor. - Changing a line quantity from 10 to 6 with the reason « Rupture partielle » adds an
OrderChangerow with both quantities and the reason. - Changing a variant's Demi-gros price from 2 390,00 DA to 2 490,00 DA HT adds a
PriceChangerow (fieldpriceDemiGros) visible in BO-28's price history. - Every reservation, release and shipment of a variant appears in BO-34 with the order number as reference.
- Archiving a product keeps its price history readable.
Data — OrderStatusChange, OrderChange, StockMovement, PriceChange, ResellerStatusChange, ResellerAssignment, CreditLimitChange, TourStatusChange, AuditLog.
Interfaces
- Screens: none dedicated
- API:
profile.updatePATCH /reseller/profile·admin.resellers.updatePATCH /admin/resellers/{resellerId}·admin.variants.priceHistoryGET /admin/variants/{variantId}/price-history·admin.orders.historyGET /admin/orders/{orderId}/history
AUD-03 — Audit log viewer with filters and export
| Release | Priority | Source | Apps | Owner tasks |
|---|---|---|---|---|
| V1 | SHOULD | cahier §10 | BO | DSH-12 |
Statement — The system shall give authorised users a searchable, filterable and exportable view of the activity journal.
Rules
- The viewer (BO-63) calls
admin.audit.list, which requiresaudit.view(granted toSUPER_ADMINby default). - Filters: actor (user picker, including Système), user type, action (several), entity type, entity id or business number, client app, IP, and a date range — default the last 7 days, at most 92 days per query (
400 VALIDATION_FAILEDbeyond). Results are sorted newest first, paginated withpage/pageSize(at most 200). - Each row shows time, actor, action, a link to the record, a one-line summary (« Statut VALIDATED → PREPARING »), app and IP; expanding it shows the before/after changes, the reason, the request id and the user agent.
- Export to CSV or XLSX of the current filter goes through the export centre (ANA-05), requires
audit.export, is limited to 100 000 rows and is itself journaled asEXPORT. - Records that have a business number (orders, resellers, invoices, tours) offer a « Journal » link that opens the viewer filtered on that record, for users holding
audit.view. - The first page answers in under 2 seconds on a journal of 10 million entries for a 7-day window.
Acceptance criteria
- A super administrator filters on
CMD-2026-000158and sees every action on that order, newest first. - Filtering on action
OVERRIDEover 30 days lists every forced validation with its reason. - A 120-day range returns
400 VALIDATION_FAILED. - A commercial administrator without
audit.viewdoes not see the menu entry and gets403 PERMISSION_DENIEDfromadmin.audit.list. - An XLSX export of the filtered view arrives in the export centre and adds an
EXPORTentry to the journal.
Data — AuditLog, ExportJob.
Interfaces
- Screens: BO-63 Activity log
- API:
admin.audit.listGET /admin/audit-logs
Roles, permissions & data scope
The eight roles, the module × action permission matrix, delegate and reseller data scopes, least privilege and server-side enforcement on every operation.
Geography, zones & GPS
The official wilaya and commune reference, sales zones assigned to delegates, the GPS capture standard with distance computation, and optional geocoding.