SRV-19 — Promotions & banners module
Promotions (percent, amount, fixed price) on products/categories/brands, targeting, schedule, stock cap, stacking rules, daily offers and banners, applied by the cart engine.
| Field | Details |
|---|---|
| Task code | SRV-19 |
| Phase | P1 — V1 build & integration |
| Product scope | V1 |
| Status | Done (Sun 18 Oct 2026) |
| Start | Sun 18 Oct 2026 |
| Due | Sun 18 Oct 2026 |
| Responsible | Anis — Full-stack developer |
| Co-responsible | — |
| Effort | 1 person-day(s) planned · 5 from scratch · size S |
| Area · app | Server · server |
| Depends on | SRV-15 |
| Unblocks | DSH-09, MOB-12, SRV-39, SRV-40 |
| Milestones | — |
Summary
Promotions (percent, amount, fixed price) on products/categories/brands, targeting, schedule, stock cap, stacking rules, daily offers and banners, applied by the cart engine.
Description
Promotions drive reseller activity (cahier §4.6, §5.5; PRM-01…PRM-05) and must be applied correctly by the cart, on top of the customer-type price (PRC-02). This task implements Promotion with the four PromotionType values (PERCENT_OFF 1–90 %, AMOUNT_OFF below the unit price, FIXED_PRICE, FREE_DELIVERY), scopes on products, variants, categories and brands (PromotionScope), targeting by wilaya, segment, customer type and volume (PromotionAudience; level targeting waits for V2 loyalty), schedule and the PromotionStatus lifecycle driven by the promotions.applySchedule job, a stock cap consumed at checkout and released on refusal or cancellation, stacking rules with priorities and an exclusive flag, daily offers with countdown and banners (Banner). It plugs the promotion engine into the pricing hook used by the cart and snapshots the applied promotion on order lines. Guests see promotions and banners without prices (decision 6). Out of scope: packs (V2, SRV-31) and the promotions UI (DSH-09).
Subtasks
| # | Subtask | Owner |
|---|---|---|
| 1 | Promotion, PromotionScope, PromotionAudience services with value validation per type and admin.promotions.crud | Anis |
| 2 | Lifecycle DRAFT → SCHEDULED → ACTIVE ↔ PAUSED → ENDED → ARCHIVED (admin.promotions.setStatus) and job promotions.applySchedule every minute | Anis |
| 3 | Eligibility evaluation per reseller (wilaya, segment, customerType, minimum quantity/amount) and per line (scope) | Anis |
| 4 | Stacking engine: priority order, exclusive promotions, best-for-reseller selection, never below zero; FREE_DELIVERY applied to the delivery fee | Anis |
| 5 | Stock cap counters consumed atomically at checkout, released on refusal/cancellation (PROMOTION_CAP_REACHED line issue) | Anis |
| 6 | Daily offer flag with endsAt countdown and Banner CRUD (image, target product/category/promotion, audience, schedule, order) via admin.banners.crud | Anis |
| 7 | admin.promotions.preview: simulate a cart for a sample reseller and show applied discounts | Anis |
| 8 | Reseller reads banners.list, promotions.list, promotions.get guest-safe (badges and discount % without prices for guests); align endpoints.json auth to optional | Anis |
| 9 | Applied-promotion snapshot on OrderItem (promotionId, discount amount) for documents and reports | Anis |
Deliverables
- apps/server/src/modules/promotions/{promotions,eligibility,stacking,caps,banners}.service.ts, router.ts, jobs.ts
- packages/contracts/src/{promotions.ts,admin/promotions.ts}
- Stacking rules section in /docs/srs/business-rules confirmed with HOCO's choices
Acceptance criteria
- A scheduled promotion becomes ACTIVE within one minute of startsAt and ENDED after endsAt; carts re-price at the next read (PRM-04)
- A promotion targeted at wilaya 31 is not applied to a reseller in wilaya 16 (PRM-02)
- When the stock cap is reached, further checkouts no longer get the discount and the cart shows PROMOTION_CAP_REACHED (PRM-04)
- With two eligible non-exclusive promotions the configured stacking rule is applied and the line total never goes below zero (PRM-03)
- A guest sees the daily offer and promotion badges but no price (AUTH-10)
- Order lines keep the applied promotion and discount even after the promotion ends
Requirements covered
| Requirement | Title | Release |
|---|---|---|
| PRM-01 | Simple promotions: daily offers, scheduled promotions, temporary discounts on products, categories or brands | V1 |
| PRM-02 | Targeting by wilaya, segment, level, brand or volume | V1 |
| PRM-03 | Configurable stacking rules and priorities | V1 |
| PRM-04 | A promotion respects its dates, stock cap and target; the cart total applies it correctly | V1 |
| PRM-05 | Home banners and daily offer carousel with countdown | V1 |
Screens
API surface
| Endpoint group | Operations |
|---|---|
| Promotions, banners & packs | 5 |
| Promotions & loyalty | 10 |
Test measures
- Unit tests for the stacking engine and value validation (table-driven)
- DB concurrency test for cap consumption at checkout
- Job test with a fake clock for schedule transitions
Risks
- Stacking rules not decided by HOCO — default to exclusive best-for-reseller and expose the rule as a setting
KPI
- Delivered by Sun 18 Oct 2026 within 1 person-day(s).
- Every acceptance criterion above demonstrated before hand-off; linked requirements' acceptance criteria pass.
- Zero open critical defects, permission gaps or data-integrity regressions at sign-off.
Generated from content/plan/tasks.json by scripts/generate-team-tasks.mjs. Dates are computed by the scheduler (Sunday–Thursday weeks, holidays excluded) — change the plan, not this page.
SRV-13 — Inventory module
Warehouses, stock levels, reservations and deductions by order status, automatic restock on cancellation and on return reception, movement ledger, thresholds and alerts, inventory sessions. Resellers only ever see availability.
SRV-10 — Geography & zones module
Wilaya/commune reference endpoints with ETag caching, zones and their membership, distance helpers.