HOCO B2B
SRS

Cross-cutting requirements

Non-functional, security and privacy requirements in measurable form — performance budgets, availability and backups, scalability, compatibility, responsive back-office, i18n and RTL, accessibility, exports, logging and alerting, security controls, privacy and quality gates — each with its acceptance and its verification.

Cahier §9 (Exigences techniques et non fonctionnelles) and §10 (Sécurité, conformité et traçabilité) state the expectations in a few lines each. This page makes every one of them measurable: an item id, the requirement, the acceptance threshold and how and where it is verified. The parent requirements are NFR-01 to NFR-09 and SEC-01 to SEC-08; thresholds marked proposed are the team's proposal for HOCO to accept at the cadrage.

How to read this page

Item ids are <parent>.<n>: NFR-1.3 is the third measurable item of NFR-01. Items whose parent is a functional requirement follow the same scheme (ACL-5.2 refines ACL-05, ANA-5.1 refines ANA-05). SEC-0.n are baseline security controls that serve every SEC requirement (cahier §10 as a whole).

Verification methods

MethodMeaningEvidence
TestAutomated test in CI (unit, integration, end-to-end)CI run linked to the release
MeasureLoad, timing or size measurement under the reference conditions belowReport attached to the task (k6 output, timings table, Sentry query)
InspectConfiguration or code review against a checklistChecklist signed in the pull request or the task
DemoExecuted scenario during acceptanceScenario evidence (acceptance scenarios)

Reference conditions used by every timing below (Assumption, calibrated during the field test MOB-13):

ConditionValue
"Normal mobile connection" (cahier §9) — profile 4G-DZ6 Mbit/s down, 1.5 Mbit/s up, 120 ms round trip, 1 % packet loss
Mid-range Android reference device4 GB RAM, Helio G85/G99 or Snapdragon 680 class, Android 13–14 (for example Samsung Galaxy A15, Xiaomi Redmi 13C)
Office connection for the back-office10 Mbit/s, 40 ms round trip, recent desktop browser
Data volumeThe generalisation column of the sizing table multiplied by 3
ServerThe production sizing of deployment and operations

Performance — NFR-01

Cahier §9 « Temps d'ouverture cible inférieur à 3 secondes sur une connexion mobile normale »; §5.1 « La recherche et les filtres retournent les résultats corrects en moins de 3 secondes »; §5.3 « apparaît immédiatement dans le back-office ».

IdRequirementAcceptanceVerified by
NFR-1.1API read latencyp95 under 300 ms server-side (request received → response sent) at 50 concurrent users for 15 minutes; mix 60 % catalog reads (list, facets, detail), 15 % cart, 10 % orders and finance reads, 10 % delegate reads, 5 % back-office lists (proposed)Measure — k6 in SRV-28
NFR-1.2API write latencyp95 under 800 ms for cart.checkout, admin.orders.validate, delegate.visits.arrive and other mutations, same load (proposed)Measure — k6 in SRV-28
NFR-1.3Catalog search and filters end to endFrom the tap on search or on a filter to the first 20 results rendered (images may still load): p90 ≤ 3 s on 4G-DZ and the reference device, with up to three combined filters (CAT-07, CAT-12)Measure — timed runs in MOB-12; Sentry transaction catalog.search p90 during the pilot
NFR-1.4Facet countscatalog.facets p95 under 400 ms server-side on the full catalog with three filters combined; counts equal the number of results returned by catalog.products.list for the same filtersMeasure (k6) and Test (count consistency) in SRV-28 and SRV-11
NFR-1.5Mobile cold startRelease build on the reference device: first frame ≤ 1.5 s, home usable with cached data ≤ 3 s, home refreshed from the network ≤ 3 s on 4G-DZ (median of 5 runs; no run above 4 s)Measure — adb shell am start -W and Sentry app-start in MOB-12; regression check in MOB-15
NFR-1.6Back-office list pagesLargest contentful paint ≤ 2 s for a 25-row table with filters applied; interaction to next paint ≤ 200 ms (proposed)Measure — Playwright with Web Vitals on the main lists in SRV-28
NFR-1.7Checkout end to endTap on « Valider la commande » → confirmation screen p90 ≤ 2 s on 4G-DZMeasure — MOB-12
NFR-1.8Live updatesCommit of a status change → reseller screen refreshed through events.stream p95 ≤ 5 s; new order → visible in the back-office queue through admin.events.stream p95 ≤ 5 s (ORD-15, SYN-07)Demo — AT-30, AT-43 with server and client timestamps
NFR-1.9Offline replaysync.batch of 50 queued mutations (photos excluded) p95 under 3 s server-sideMeasure — SRV-28
NFR-1.10Payload and asset budgetsCursor list page of 20 items ≤ 60 KB gzip; thumbnails WebP ≤ 30 KB at 320 px; detail images ≤ 200 KB at 1 280 px; download size ≤ 35 MB per app on arm64Measure — response-size test in CI; image pipeline test; Play Console size report in MOB-14
NFR-1.11DocumentsInvoice or delivery-note PDF generated p95 under 5 s; larger documents generated asynchronously with a notificationMeasure — SRV-28

Exports have their own budget (ANA-5.3).

Availability, backups and restore — NFR-02, SEC-05

Cahier §9 « Service supervisé avec sauvegardes et procédure de restauration »; §10 « Sauvegardes automatiques, politique de rétention et tests de restauration ».

IdRequirementAcceptanceVerified by
NFR-2.1Monthly availability≥ 99.5 % for the API, the back-office and the reseller web (about 3 h 40 min of unplanned downtime per month), announced maintenance excluded (proposed)Measure — external uptime monitor, monthly support report
NFR-2.2Planned maintenanceWindow Friday 06:00–09:00 Africa/Algiers, announced 48 h ahead (announcement + banner); during it the API answers 503 MAINTENANCE with details.until and the apps show their maintenance state (RA-36, DA-28)Demo — maintenance mode switched on in pre-production
NFR-2.3Field work survives an outageA delegate completes a full tour with no server (offline-first, SYN-04); everything syncs afterwards without loss or duplicateDemo — AT-15
NFR-2.4Recovery point objective≤ 15 minutes with continuous WAL archiving (point-in-time recovery); ≤ 24 hours if the hosting option offers only nightly dumps (proposed, D-15)Inspect — backup configuration in OPS-02
NFR-2.5Recovery time objective≤ 4 hours from the decision to restore to the service open again, following the restore runbook (proposed)Measure — timed restore drill in SRV-28 and every quarter
SEC-5.1Automatic backupsNightly logical dump at 02:00 plus WAL archiving; private object storage versioned and copied nightly; all copies off the production server, on another provider or accountInspect — OPS-02; alert if no successful backup by 04:00
SEC-5.2Retention7 daily, 4 weekly and 12 monthly copies; deleted personal data therefore persists in backups up to 12 months, which the privacy policy statesInspect — lifecycle rules of the backup bucket
SEC-5.3EncryptionDumps encrypted before upload (public-key encryption; the private key held offline by Anis and a person designated by HOCO); bucket encryption at rest enabledInspect — OPS-02
SEC-5.4Restore testsMonthly restore of the latest dump into a scratch database with integrity checks (row counts, last business numbers, migration status); logged with duration and resultMeasure — restore log; first run in SRV-28

Scalability — NFR-03

Cahier §9 « Architecture capable d'augmenter le nombre de revendeurs, produits, commandes et zones ». The cahier gives no volumes; the table below is the team's assumption, to be confirmed by HOCO at the cadrage, and drives the sizing and the load tests.

DimensionPilotGeneralisation (12 months)Design headroom
Active resellers403 00010 000
CRM records (prospects included)2008 00030 000
Delegates · staff users3 · 1030 · 25100 · 60
Products · variants1 500 · 2 5002 000 · 3 50010 000 · 20 000
Orders per day (average · peak)10 · 30300 · 1 0003 000 · 10 000
Lines per order (average)121212
Visits per day404501 500
Location pings per day1 00010 00040 000
Photos per day809003 000
Concurrent reseller SSE connections (peak)306002 500

Derived growth at generalisation: database under 20 GB per year (orders and lines about 1 GB, audit and notifications the largest tables); object storage about 70–100 GB per year, mostly visit and store photos — the reason visit-photo retention is in D-11.

IdRequirementAcceptanceVerified by
NFR-3.1Headroom without code changeNFR-1.1 and NFR-1.2 met with the generalisation data ×3 on the production sizing; the design headroom reached by vertical scaling and API replicas onlyMeasure — SRV-28 with a seeded volume
NFR-3.2Stateless APINo session, cache or SSE subscription state in process memory that another replica needs: sessions in PostgreSQL, rate limits and SSE fan-out through Redis pub/sub; two api replicas pass the end-to-end suiteTest — CI job with two replicas behind a proxy
NFR-3.3Safe background jobsEvery job idempotent; scheduled jobs run once even with several worker processes (repeatable-job keys); a job retried after a crash produces the same resultTest — job tests in SRV-08
NFR-3.4Large tablesKeyset pagination on every list; LocationPing, AuditLog, Notification and StockMovement indexed on their access paths and purged or archived by retention jobs; no query in the p95 path scans a full tableInspect — slow-query and index pass (pg_stat_statements) in SRV-28
NFR-3.5Search enginePostgreSQL full-text search with unaccent and trigram indexes up to the design headroom; a dedicated search engine is not part of V1 (Assumption)Measure — NFR-1.3 and NFR-1.4 at headroom volume

Compatibility — NFR-04

Cahier §9 « Android prioritaire ; iOS selon décision du client ; téléphones milieu de gamme ».

IdRequirementAcceptanceVerified by
NFR-4.1Android versionsReseller app minSdk 24 (Android 7.0); delegate app minSdk 26 (Android 8.0, notification channels and foreground-service behaviour); targetSdk = the level Google Play requires at submission time (proposed; Imad confirms in MOB-01, the mobile guide is authoritative)Inspect — Gradle configuration
NFR-4.2Device coverageEvery release passes the smoke suite on the tier-1 devices; every store release on tier 1 and tier 2 (table below)Demo — device matrix in MOB-12, MOB-15
NFR-4.3iOSOnly if D-10 says so: iOS 15 or later, same feature setInspect — MOB-16
NFR-4.4BrowsersBack-office and reseller web: the last two versions of Chrome, Edge and Firefox, Safari 16.4 or later; reseller web also on Chrome for Android and Samsung Internet (last two versions)Test — Playwright on Chromium, Firefox and WebKit
NFR-4.5Screen sizesApps from 360 × 640 dp to 430 dp wide in portrait, font scale 0.85–1.3; reseller web from 360 px to 1 920 px; back-office per NFR-05Demo — design QA DQA-02, DQA-03, DQA-05
TierDevices (proposed — the pilot users' phones are surveyed at the cadrage)Why
1Samsung Galaxy A15 or A16 (Android 14–15) · Xiaomi Redmi Note 13 or Redmi 13C (HyperOS) · the model most used by HOCO's delegatesReference mid-range; aggressive battery management on Xiaomi
2An Oppo or Realme A-series phone (ColorOS) · a 2–3 GB RAM phone on Android 10–11 · an Android 7 or 8 emulator for the minimum SDKBattery savers, low memory, oldest supported system
3 (if iOS)iPhone SE (2nd generation or later) and a recent iPhoneSmallest and current screens

Responsive back-office — NFR-05

Cahier §9 « Back-office utilisable sur ordinateur, tablette et grand écran ».

WidthLayout
≥ 1 920 pxDashboards spread to more cards per row; tables show optional columns; content width capped for forms
1 280–1 919 pxReference layout: expanded sidebar, full tables
1 024–1 279 pxSidebar collapsed to icons; secondary columns hidden behind a column picker
768–1 023 px (tablet)Sidebar as a drawer; tables scroll horizontally with a sticky first column; forms in one column; drawers become full-screen sheets
Below 768 pxConsultation and quick actions only (orders to confirm, validation queue, order detail); not optimised for data entry
IdRequirementAcceptanceVerified by
NFR-5.1Every back-office page usable from 1 024 pxNo horizontal page scroll at 1 024 px (tables scroll inside their container); every action reachableDemo — DQA-04 at 1 024, 1 280 and 1 920 px
NFR-5.2Tablet useOn a 10-inch tablet in landscape, the orders-to-confirm queue, order detail, delivery board and validation queue are fully operable by touch; targets ≥ 40 pxDemo — DQA-04 on a real tablet
NFR-5.3Large screensAt 2 560 px the dashboards fill the width without stretched charts; text line length stays readableDemo — DQA-04

Languages, internationalisation and RTL — NFR-06

Cahier §9 « Français en V1 ; arabe et anglais prévus selon validation ». French is the only active language at launch unless D-09 decides otherwise; everything is built so that Arabic and English are a translation and QA job, not a refactor.

IdRequirementAcceptanceVerified by
NFR-6.1No hard-coded textEvery user-facing string comes from message files: ARB (app_fr.arb, app_ar.arb, app_en.arb) in Flutter, next-intl JSON in the Next apps; server errors and templates per localeTest — pseudo-locale build (accented, 30 % longer strings) shows no untranslated text on the main screens; CI fails on keys missing from ar or en files (empty values allowed, they fall back to fr)
NFR-6.2ICU messagesPlurals, gender and variables use ICU MessageFormat; no string concatenation of sentence fragmentsInspect — code review checklist
NFR-6.3Locale negotiationUser locale from the profile (me.update); API messages follow Accept-Language (fr default, ar, en); enum values are never sent as labels — clients translate themTest — API returns Arabic messages with Accept-Language: ar
NFR-6.4Logical layoutWeb: CSS logical properties only (margin-inline-start, padding-inline-end, inset-inline-start, text-align: start; Tailwind ms-*, me-*, ps-*, pe-*, start-*, end-*); physical ml-*, mr-*, left-*, right-* forbidden for layout. Flutter: EdgeInsetsDirectional, AlignmentDirectional, PositionedDirectionalTest — CI grep rule on the web apps; Flutter lint rule in MOB-07
NFR-6.5Directionar sets dir="rtl" and lang="ar" on the web and TextDirection.rtl in Flutter; directional icons (back, chevrons, progress arrows) mirror; non-directional icons (play, check, clocks, brand logos) do notDemo — AT-31
NFR-6.6Arabic typographyAn Arabic typeface paired with the Latin one in the design system (DES-02), self-hosted; Arabic line height about 1.5; no letter-spacing and no uppercase transform on Arabic textInspect — design tokens; Demo AT-31
NFR-6.7Numbers, money and datesfr-DZ formats: 125 000,00 DA, 03/11/2026, 24-hour time; Arabic uses the ar-DZ locale with Latin digits; the currency label in Arabic is part of D-09; Gregorian calendar; all times shown in Africa/AlgiersTest — formatter unit tests in MOB-07 and the web apps
NFR-6.8Mixed-direction stringsBusiness numbers, phone numbers, amounts and product references inside Arabic text are isolated as left-to-right (<bdi> or dir="ltr" on the web, an LTR TextSpan in Flutter)Demo — AT-31
NFR-6.9Reference dataWilaya and commune names in French and Arabic (GEO-01); translatable content (categories, attributes, promotions, announcements) stored so that an Arabic value can be added without a schema changeInspect — database design review
NFR-6.10Text expansionLayouts tolerate 30 % longer labels without truncating actions or amounts; buttons have no fixed widthDemo — pseudo-locale screenshots in DQA-02 to DQA-05

Accessibility — NFR-07

Cahier §9 « Contrastes lisibles, boutons accessibles, tailles de texte cohérentes et messages explicites ». Target: WCAG 2.1 level AA for what applies to each interface (proposed).

IdRequirementAcceptanceVerified by
NFR-7.1ContrastText ≥ 4.5:1, large text and UI components (borders of inputs, status pills, icons that carry meaning) ≥ 3:1, in every status tone of the design systemTest — Flutter textContrastGuideline; axe-core on the web pages; token check in DES-02
NFR-7.2Touch targets≥ 48 × 48 dp in the apps, ≥ 40 × 40 px for back-office controls, ≥ 24 × 24 px minimum spacing for dense tablesTest — Flutter androidTapTargetGuideline; Inspect — design QA
NFR-7.3Text scalingApps usable at system font scale 1.3 without clipped amounts, buttons or status; web usable at 200 % browser zoomDemo — MOB-17, DQA-04
NFR-7.4Screen readersEvery icon-only button has a label (Flutter Semantics, web aria-label); status pills expose their text; images have alternatives or are decorativeTest — Flutter labeledTapTargetGuideline; axe-core: zero serious or critical violations on the main pages
NFR-7.5Not by colour aloneStatus, stock availability and validation errors always combine colour with text or an iconInspect — design QA
NFR-7.6KeyboardBack-office fully operable with the keyboard: visible focus, logical tab order, dialogs trap focus and close with Escape, tables navigableTest — Playwright keyboard paths on the orders-to-confirm queue and the order detail
NFR-7.7Explicit messagesEvery error says what happened and what to do next, in French, from the error code's localised message; no raw codes or stack traces shown to usersInspect — copy review in DQA-10
NFR-7.8Outdoor readabilityDelegate app readable in direct sunlight at full brightness: key screens use the high-contrast tones of the design systemDemo — DQA-03 outdoor check

Exports — ANA-05

Cahier §9 « PDF et Excel/CSV pour les listes et rapports autorisés »; ANA-05.

IdRequirementAcceptanceVerified by
ANA-5.1FormatsLists and reports export to XLSX and CSV; reports and documents to PDF (ExportFormat); XLSX amounts are numbers formatted in DA with two decimals, dates real dates; CSV is UTF-8 with BOM and ; separator so that French Excel opens it correctlyTest — export snapshot tests in SRV-25
ANA-5.2PermissionExporting needs <module>.export (for example crm.export, reports.export); the export contains only rows and columns the requester may see (purchase prices only with the pricing permission, ACL-04)Test — permission tests; Demo AT-27
ANA-5.3Size and durationAsynchronous ExportJob; up to 100 000 rows, streamed (bounded memory); 10 000 rows in under 30 s, a 50-page PDF in under 60 sMeasure — SRV-28
ANA-5.4Protected filesStored as GENERATED_DOCUMENT in the private bucket, downloaded through a 5-minute signed URL issued to the requester only, deleted after exports.retentionDays (default 7)Test — SRV-25
ANA-5.5TraceabilityAuditLog EXPORT with the filters used and the row countTest — SRV-25

Logging, monitoring and alerting — NFR-08

Cahier §9 « Journalisation des actions sensibles et erreurs techniques »; §10 « Journal d'activité : connexions, créations, modifications, validations, exports et suppressions ». Two separate records exist: the activity journal (AuditLog, business-facing, kept per the retention table, AUD-01) and technical logs (operations-facing, 30 days).

What technical logs contain

SourceFields
API request log (pino, JSON)requestId, timestamp, operation id, method, route template (not the full URL with query), status, duration, userId (UUID), userType, ClientApp, app version, error code
Worker job logQueue, job id, attempt, duration, outcome, error code
Security eventsSign-in success and failure (user id or masked phone), lockouts, permission denials, rate-limit hits, 426 version refusals
Integration callsProvider, operation, status, latency, provider message id (never the content of SMS or emails)

What is never logged — enforced by pino redact paths, Sentry beforeSend scrubbing with sendDefaultPii off, and a test that sends a request containing each field and asserts it is absent from the log output:

Never in logsWhy
Passwords, temporary passwords, OTP codes, verification tokensCredentials
Session tokens, Authorization and Cookie headers, FCM tokens, signed URLsReplayable secrets
Full phone numbers and emailsPersonal data — masked as +213 55* ** ** 56
Coordinates (check-in positions, location pings, the location sent to support.whatsapp)Location data lives only in the database under its retention rule — never in logs, traces or error reports
Request and response bodies of auth, finance and files operationsPersonal and financial data
Content of payment proofs, documents and photosPersonal data
IdRequirementAcceptanceVerified by
NFR-8.1CorrelationEvery request has a requestId returned in the error envelope and the X-Request-Id header, propagated to jobs it enqueues and to SentryTest — SRV-04
NFR-8.2RedactionThe redaction test above passes; no field of the "never" list appears in a log, trace or error reportTest — CI
NFR-8.3Error trackingSentry in the server, both Next apps and both Flutter apps, with release tags, source maps and Dart symbols uploaded by CI; crash-free sessions ≥ 99.5 % during the pilotMeasure — Sentry release health
NFR-8.4MetricsRequest rate, latency percentiles and error rate per operation; queue depth, oldest waiting job and failed jobs per queue; database connections and slow queries; disk; SSE connections; SMS delivery rate and push failure rateInspect — dashboards in OPS-02
NFR-8.5AlertingEvery alert of the alert table reaches the on-call person within 5 minutes; a test alert is fired before go-liveDemo — go-live checklist
NFR-8.6Log retentionTechnical logs 30 days; Sentry events 90 days; AuditLog per the retention tableInspect — OPS-02
NFR-8.7Activity journal completenessSign-ins, failures, creations, modifications, status changes, validations, rejections, overrides, exports, imports, permission changes and deletions are journaled with actor, time, app, IP and before/after valuesTest — journal assertions in each module's integration tests; Demo AT-14

Security controls

Authentication and sessions — SEC-01, SEC-02

IdRequirementAcceptanceVerified by
SEC-1.1Password storageMemory-hard hashing (Better Auth's default scrypt, or Argon2id) with per-user salt; no reversible storage; parameters reviewed in SRV-28Inspect — SRV-05
SEC-1.2Password policy8 to 128 characters for resellers and delegates, 10 minimum for staff; any character allowed; refused if among the most common passwords or equal to the phone number (AUTH-07)Test — SRV-05
SEC-1.3One-time codes6 digits, valid 5 minutes, 5 attempts, resend after 60 s, 5 per hour per phone and 20 per hour per IP; stored hashed; invalidated after useTest — SRV-05; Demo AT-33
SEC-1.4Temporary passwordsCreated by admin.users.create or reset: valid 72 hours, single use, change forced at first sign-inTest — SRV-05
SEC-2.1Session lifetimeResellers and delegates 30 days sliding; back-office 7 days sliding with re-authentication for sensitive actions (D-33)Test — SRV-05
SEC-2.2RevocationSign-out revokes the current session and unregisters its push token; a password change revokes the other sessions; suspension or deactivation revokes all sessions at once; a user can list and revoke their sessions (AUTH-06)Test — SRV-05; Demo AT-32
SEC-2.3Attempt limitingSign-in 5 attempts per minute per phone and IP, lockout 15 minutes after 5 consecutive failures; generic error message that does not reveal whether the phone existsTest — SRV-05
SEC-2.4Token handling on clientsMobile tokens in secure storage (Android Keystore through flutter_secure_storage), never in logs or plain preferences; web sessions in HttpOnly, Secure, SameSite=Lax cookies with an environment-specific name so staging and production sessions never mixInspect — MOB-02, DSH-01

Access control on every operation — ACL-05

Cahier §10 « Contrôle d'accès par rôle et permission sur chaque API »; §3.1.

IdRequirementAcceptanceVerified by
ACL-5.1Declared permission on every routeEvery back-office operation declares its permission key in the contract; every reseller operation the self scope; every delegate operation the delegate scope; public and optional operations are listed explicitlyTest — a sweep test enumerates all contract routes and fails if one has no declared rule (SRV-06, SRV-28)
ACL-5.2Scope as query filterScopes are applied in the data-access layer, not in handlers; a record out of scope answers 404 NOT_FOUND so its existence does not leakTest — per-module scope tests; Demo AT-22, AT-23
ACL-5.3Field-level restrictionsPurchase prices, margins and credit data only for holders of the matching permission (ACL-04); delegate order views never include purchase pricesTest — response-schema tests per role
ACL-5.4Quantities never leave the back-officeReseller, guest and delegate response schemas contain no stock quantity field — only availability IN_STOCK or OUT_OF_STOCK (STK-07); the contract test fails if such a field appearsTest — contract snapshot; Demo AT-41
ACL-5.5Guest accessoptional-auth catalog operations return no price (price: null) and no customer-type information without a session; cart and order operations refuse guestsTest — catalog tests in SRV-11; Demo AT-38
ACL-5.6UI mirrors the serverThe apps hide what the user cannot do, using me.get permissions and allowedActions; hiding is never the protectionDemo — AT-14

Input validation and API hardening

IdRequirementAcceptanceVerified by
SEC-0.1Strict input schemasEvery input validated by Zod 4 strict objects: unknown fields rejected (400 VALIDATION_FAILED), string lengths bounded (notes ≤ 300 characters, messages ≤ 2 000), quantities within allowed ranges, enums exact, phones normalised to E.164, ids UUIDv7, dates ISO-8601Test — contract tests in SRV-03
SEC-0.2Output schemasResponses typed by the contract and stripped of fields outside it, so a new database column cannot leakTest — contract snapshot
SEC-0.3InjectionDatabase access through Prisma; raw SQL only with tagged templates — $queryRawUnsafe with user input is forbidden (CI grep rule); no HTML rendering of user input without escaping (PDF templates included)Test — CI rule; Inspect
SEC-0.4Browser protectionsStrict Content-Security-Policy with nonces on the Next apps, X-Content-Type-Options: nosniff, Referrer-Policy: strict-origin-when-cross-origin, Permissions-Policy (no camera, microphone or geolocation on the back-office), frame-ancestors 'none'; CORS allow-list of the exact app origins with credentials; state-changing cookie requests must come from an allowed OriginInspect — headers check in SRV-28
SEC-0.5Abuse limitsGeneral limit 600 requests per minute per user; anonymous catalog and invitation calls limited per IP (30 per minute for invitations; proposed 120 per minute for guest catalog calls) to make bulk scraping of the guest catalog slow; 429 RATE_LIMITED with Retry-AfterTest — SRV-04
SEC-0.6Version enforcementBelow the minimum version the API answers 426 UPGRADE_REQUIRED (AUTH-09) so a vulnerable app version can be retiredDemo — AT-28

Files and documents — SEC-04

Cahier §10 « Protection des documents et fichiers téléchargés ».

IdRequirementAcceptanceVerified by
SEC-4.1Private by defaultOnly product images, brand logos and banners are public (CDN); every other FilePurpose lives in the private bucket, which denies public accessInspect — bucket policies in OPS-02
SEC-4.2Upload checksThe pre-signed PUT (10 minutes) is bound to the declared MIME type; files.completeUpload checks the stored object's real size against the purpose's limit (5 MB for photos, 10 MB for documents, proofs and attachments) and its magic bytes against the allowed types, and deletes it on mismatchTest — SRV-07
SEC-4.3Image sanitisingImages are re-encoded (thumbnails and display sizes), which strips EXIF metadata including GPS; originals of photos are not servedTest — SRV-07
SEC-4.4Signed downloadsPrivate files are read through 5-minute signed GET URLs issued after an access check of the caller on the owning record; URLs are never loggedTest — SRV-07; Demo AT-22
SEC-4.5Malware scanningDocuments, payment proofs and ticket attachments scanned before staff can open them (recommended; a scanner container costs about 1–1.5 GB of RAM — decided with the sizing in D-15)Inspect — OPS-02

Transport — SEC-03

IdRequirementAcceptanceVerified by
SEC-3.1HTTPS everywhereTLS 1.2 or later (1.3 preferred) on every public endpoint; HTTP redirects to HTTPS; certificates renewed automatically with an alert 14 days before expiryInspect — TLS scan in OPS-02
SEC-3.2HSTSStrict-Transport-Security one year, includeSubDomains once every subdomain is HTTPSInspect — headers check
SEC-3.3No clear-text mobile trafficAndroid network security configuration forbids clear text in staging and production flavors; no certificate pinning in V1 (automatic certificate rotation would break pinned apps)Inspect — MOB-01

Secrets, dependencies and infrastructure

IdRequirementAcceptanceVerified by
SEC-0.7Secrets managementSecrets only in the environment of each deployment (Dokploy) and in GitHub Actions secrets, validated at boot by the env package; one set per environment; never in the repositories; rotation runbook (deployment and operations) applied on any suspected leak and on every team departureInspect — OPS-02
SEC-0.8Secret scanninggitleaks in the pre-commit hook and as a CI job on every push of both repositories; a finding fails the buildTest — CI
SEC-0.9Dependency scanningDependabot (npm, pub, GitHub Actions, Docker); pnpm audit --prod fails CI on high or critical issues with a fix available; container images scanned before deploy; monthly dependency update roundTest — CI; Inspect — monthly maintenance report
SEC-0.10Least privilege on infrastructureSSH by key only, no root login, firewall open on 80 and 443 only (SSH restricted); database and Redis reachable only on the internal network; separate database roles for the application (data only), migrations (schema) and backups; storage credentials per bucket and per environment; Firebase service account limited to sending messages; Dokploy and provider consoles behind two-factor authenticationInspect — infrastructure checklist in OPS-02 and SRV-28
SEC-0.11PatchingOperating-system security updates applied automatically; PostgreSQL and Redis minor updates monthly; critical vulnerabilities patched within 7 days (proposed)Inspect — monthly maintenance report

Account deactivation without losing history — SEC-06

IdRequirementAcceptanceVerified by
SEC-6.1Deactivate, never deleteUsers go SUSPENDED or DISABLED (admin.users.setStatus); their orders, visits, tours, payments and journal entries stay intact and attributed; foreign keys never cascade deletes onto historyTest — SRV-05; Demo AT-32
SEC-6.2Delete means archiveDeleting a referenced business record (brand, category, reference item) archives itTest — module tests
SEC-6.3Erasure by anonymisationA personal-data erasure replaces names, phones, emails and photos by placeholders while keeping legally required records (privacy)Test — anonymisation script test

Privacy and compliance — SEC-07, SEC-08

Cahier §10 « Consentement et transparence concernant la géolocalisation des délégués » and « Politique de confidentialité, propriété et durée de conservation des données à valider avec le client ». The applicable law is Law 18-07 of 10 June 2018 on the protection of natural persons in the processing of personal data, supervised by the national authority (ANPDP). HOCO is the data controller; the development team acts as a processor during build and maintenance. Every legal point below is to validate with HOCO's counsel.

IdRequirementAcceptanceVerified by
SEC-7.1Informed consent before the first tourDA-04 explains in plain French what is collected (positions during tours only), how often (every 5 minutes or 200 m, D-07), who sees it (users with field.view), how long it is kept (90 days) and how to stop it (suspend or close the tour); the consent is recorded with the text version, date and app version, and asked again when the text changesTest — MOB-10; Demo AT-09
SEC-7.2No tracking outside toursSampling runs only while a tour is IN_PROGRESS (foreground service with a persistent notification, D-24); pings received for a tour in any other status are discarded and countedTest — SRV-21 and MDA-12; Demo AT-09
SEC-7.3TransparencyThe delegate can see in DA-26 whether location is active, the consent given and the retentionDemo — AT-09
SEC-7.4Proportionate accessTrails visible only to field.view holders, per tour; exports of trails are not offered in V1Test — permission tests
SEC-7.5Labour-law fitThe use of positions for performance review is described in the delegates' working rules (to validate with HOCO's counsel)Inspect — HOCO's sign-off

Data minimisation

  1. Only the data sets of cahier §15.4 and §15.5 are collected; identity documents (ID_CARD) are optional and visible only to users with crm.validate and finance roles (proposed).
  2. Device location for the WhatsApp support region (SUP-05) is used on the device and sent to support.whatsapp only to resolve the nearest commune, wilaya and region; it is never stored, logged or attached to the guest or the account, and it is requested only when the user taps the button without a declared wilaya (Android permission while using the app; refusing leads to the wilaya picker).
  3. No access to contacts, call logs or SMS inboxes; the OTP is read through the SMS User Consent or Retriever APIs, which need no SMS permission.
  4. No advertising identifiers, no third-party analytics or trackers in the apps; Firebase is used for messaging only; crash reports carry no personal data (NFR-8.2).
  5. Photos are stripped of metadata (SEC-4.3); store photos show the shop, not people, as instructed in the delegate field guide.

Retention

Proposed durations — to validate with HOCO's counsel and accountant (D-11). Each duration is a setting applied by a purge or anonymisation job.

Data categoryProposed retentionThenBasis (to validate)
Reseller account and CRM recordWhile the commercial relationship lastsAnonymised 3 years after the last order or interactionContract; legitimate interest
Prospect never converted (NOT_INTERESTED or no activity)3 years after the last interactionAnonymisedLegitimate interest
Orders, invoices, credit notes, payments, delivery notes, payment proofs10 yearsDeletedCommercial and tax record keeping — to confirm with HOCO's accountant
Returns and after-sales claims with photos3 years after closure; photos 2 yearsDeletedWarranty disputes
Location pings (LocationPing)90 daysDeleted (daily kilometre totals kept with the tour)Consent and legitimate interest (D-07)
Visit records (check-in position, checklist, report)3 yearsAnonymised delegate link kept for statisticsLegitimate interest
Visit photos · store photos2 years · while the reseller is activeDeletedLegitimate interest
Store documents (RC, NIF, NIS, AI, ID)While the reseller is active + 1 yearDeletedContract
Support tickets and messages3 years after closureDeletedLegitimate interest
Notifications (inbox) · delivery records12 months · 90 daysDeletedService
One-time codes · SMS send logUntil expiry + 24 hours · 90 daysDeletedSecurity
Sessions · device push tokensUntil expiry or revocation + 30 days · until sign-out or 60 days without activityDeletedSecurity, service
Activity journal (AuditLog)5 yearsDeletedSecurity and accountability
Technical logs · error reports30 days · 90 daysDeletedSecurity
Idempotency records30 daysDeletedService
Export files · import files7 days · 90 daysDeletedService
Invitations and funnel events12 months after the last stepAggregatedLegitimate interest
Backups12 months (rolling)OverwrittenSecurity

Data subject requests

RequestHow it is madeHow it is fulfilledTarget
InformationPrivacy policy linked from sign-up, settings and the store listingsPublished before the Play closed track (MOB-14)Before go-live
Access and portabilitySupport ticket or email to HOCO's contact, identity confirmed by an OTP to the account's phoneSuper admin runs the personal-data export (JSON and PDF) — logged in the journal30 days (to validate)
RectificationProfile screens for editable fields; support for the restBack-office edit, audited7 days
Objection to marketingNotification preferences (NOT-06)ImmediateImmediate
Erasure and account deletionIn-app « Supprimer mon compte » request and a web page (required by Google Play for apps with account creation)Account closed; personal data anonymised except records under legal retention; confirmation sent30 days (to validate)
Withdrawal of geolocation consent (delegates)Settings or HRLocation stops; the use of the delegate app without location is defined with HOCO's counselImmediate

Processors and transfers

Every provider that handles personal data needs a contract with data-protection terms, a known data location and — when data leaves Algeria — the authorisation or legal basis that Law 18-07 requires (to validate with HOCO's counsel; hosting location is D-15).

Processor (category)Personal data handledLocation to document
Hosting and database (VPS)EverythingProvider's data centre
Object storage and backupsPhotos, documents, proofs, dumpsProvider's region
Google Firebase (FCM, App Distribution)Push tokens, notification texts, testers' emailsGoogle infrastructure
Google Maps PlatformStore coordinates sent for geocodingGoogle infrastructure
SMS gatewayPhone numbers, message textsGateway's infrastructure
Email providerStaff and reseller emails, message contentProvider's region
SentryTechnical error context (scrubbed of personal data)Sentry region chosen at setup
GitHub (repository and documentation)No production personal data—

Quality — NFR-09

Cahier §13.4 (maintenance) requires a maintainable platform; NFR-09.

LayerTestsGate
Server domain logicUnit tests (Vitest): price resolution by customer type, promotion application, state machines, stock arithmetic (reservation, release, automatic restock on cancellation and return reception), credit exposure, permission guard, GPS distanceLine coverage ≥ 80 % on domain modules (proposed)
Server modulesIntegration tests against a real PostgreSQL and Redis (CI services): every procedure's happy path, permission and scope denials, main error codesAll pass; overall coverage ≥ 60 %
API contractOpenAPI snapshot diff on every pull request; breaking changes need the contract-breaking label and a note to ImadNo unlabeled breaking change
Databaseprisma migrate diff shows no drift; migrations are additive (expand/contract)Clean diff
Back-office and reseller webComponent tests for complex widgets; Playwright end-to-end smoke: sign-in, confirm an order, verify a payment, resolve a claim, receive a return, reseller checkout on the webAll pass on Chromium; weekly on Firefox and WebKit
Flutter appsUnit tests (formatters, offline outbox, SSE reconnection), golden tests of hoco_ui widgets, integration tests of the ordering and visit flows on an emulator (MOB-15)All pass; flutter analyze clean
Securitygitleaks, dependency audit, redaction test (NFR-8.2), permission sweep (ACL-5.1), no-quantity contract test (ACL-5.4)All pass
Documentationcheck-mdx on the docs siteNo problem

CI on every pull request runs: Biome lint and format, TypeScript type-check, the tests above, the contract diff, the migration check, image builds, gitleaks and the dependency audit (and, in hoco-mobile, dart format, flutter analyze, tests and an APK build). A pull request merges only when CI is green and the definition of done is met.

Verification plan

TaskVerifies
SRV-04 · SRV-05 · SRV-06 · SRV-07NFR-8.1, SEC-0.5, SEC-1.x, SEC-2.x, ACL-5.1–5.3, SEC-4.2–4.4
OPS-02NFR-2.4, SEC-3.x, SEC-4.1, SEC-5.1–5.3, SEC-0.7–0.11, NFR-8.4, NFR-8.6
SRV-28NFR-1.1, 1.2, 1.4, 1.6, 1.9, 1.11, NFR-2.5, SEC-5.4, NFR-3.1–3.5, ANA-5.3, SEC-0.4, permission sweep
MOB-12 · MOB-13 · MOB-15 · MOB-17NFR-1.3, 1.5, 1.7, NFR-4.2, NFR-7.1–7.4
DQA-02 · DQA-03 · DQA-04 · DQA-05NFR-4.5, NFR-5.x, NFR-6.10, NFR-7.5, NFR-7.8
QA-01 · QA-02Every Demo item through the acceptance scenarios

On this page