Merit · Al Fursan Store · internal proposal
Promo codes for Al Fursan, before Saudi National Day arrives
Al Fursan Store wants promo codes live for Saudi National Day. That date is fixed and external. It does not move for our roadmap.
Revision history
| Date | Change | Source |
|---|---|---|
| 21 July 2026 | First issue, from the requirements workshop of 20 July 2026. | Requirements workshop |
| 3 August 2026 | Data architecture settled. Member tier is resolved
live from Al Fursan's Accenture API at the moment a code is validated.
Merit stores no member tier, no PII, and no Al Fursan member data of
any kind, at any point. There is no caching path and no data sync.
This replaces the earlier proposal to sync or cache member data, so
gating item 1, the Merit security and compliance approval to persist
tier against an anonymous member ID, is moot and closed,
and TR-05 is retired. Phase 2 gains a basic per-campaign promo code stacking toggle, off by default, campaigns opt in. This is distinct from, and far smaller than, the stacking-groups and A/B testing framework, which stays deferred to a separate 2027 document, PRD_Promo_Engine_V2_Stacking_AB.md. Phasing restated: Phase 1 generic store-wide codes, approved for the next sprint against Saudi National Day; Phase 2 segmented codes, category and product scoping, tier-differentiated discount, and the stacking toggle; Phase 3 vouchers and influencer codes with attribution. |
Marketplace Sprint Backlog Review, 3 August 2026 |
| 3 August 2026 | Three consequences of the same decision, recorded after a second pass over the discussion. The Al Fursan member ID is named as the anchor attribute the two systems refer to a member by, constant from profile creation, with email and phone ruled out for that role because both change over time. The case against a nightly batch is stated on its own terms, independently of privacy: Merit knows only the members who have signed in, so a batch either answers for a minority of the base or requires the full member list. The cost at campaign creation is stated openly: the creation screen cannot size an audience, and restoring that would be a separate data-sharing conversation rather than a Phase 2 dependency. | Marketplace Sprint Backlog Review, 3 August 2026 |
The ask
Al Fursan asked Merit, in the requirements workshop of 20 July 2026, for the ability to issue discount codes members enter at checkout, so the store can run seasonal, category, and influencer campaigns tied to Saudi National Day and the calendar moments after it.
Merit has no promo capability in production today. There is no mechanism to offer a discount without a manual PIM price change, which is irreversible, untargeted, and not trackable as promotion activity.
Where promo codes would sit
Al Fursan Store is one tenant on the Merit platform. Every box a member touches between opening the app and paying already exists. None of them can apply a promo code today.
Al Fursan Store sits between its members and Merit checkout and OMS. Every box exists. None of them can apply a code.
In scope for this document
- How the Phase 1 machine validates a code and settles a redemption.
- What breaks, and what happens when it does.
- The five business decisions that block Phase 1 from being scoped.
Out of scope for this document
- The full requirement list. That lives in the PRD.
- The client commitment and campaign phasing. That lives in the BRD.
- Tier differentiation and member binding. Those are Phase 2 and Phase 3.
Saudi National Day is a fixed date. This PRD currently sits at P2 for Q3 to Q4 2026, which is after it. Either Phase 1 is pulled forward, or Al Fursan runs Saudi National Day without codes. That is gating item 11, and it is Brian's to resolve.
The sequencing conflict, as a picture
The current plan delivers after the date it exists for. Gating item 11, drawn instead of written.
What this document is
This is the how. The what and the why are in the PRD. The client commitment is in the BRD.
| Document | Answers | Owner | Status |
|---|---|---|---|
| Promotions Engine V1 PRD | The what and the why: every requirement, condition, and phase. | Brian Arfi Faridhi | Draft, v1.1 |
| Al Fursan Store BRD | The client commitment: what Al Fursan is promised, and by when. | Brian Arfi Faridhi | Draft for review |
| This proposal | The how: the machine, what breaks, and the five decisions blocking Phase 1. | Brian Arfi Faridhi | Internal, this document |
02 · the problem
Two problems. The second is the one people miss.
The first is straightforward. The second changes how every campaign has to be built, priced, and reported.
Problem one: no promo engine exists
There is no code field, no condition engine, no redemption record. It gets built. That part is not interesting.
Problem two: a redemption is not final at checkout
On Al Fursan, loyalty miles are credited 30 days after an order is accepted, and they are cancelled if the order is cancelled or returned inside that window. A promo redemption inherits the same clock.
Thirty days, then a fork
Every campaign number is provisional until this fork resolves.
Every hard open question in this document hangs off that one fact. Four consequences follow, and none of them are optional to handle.
- A campaign cannot be reported as successful on the day it ends. It has not settled.
- "How many redemptions did we get" has two different correct answers at any given moment, Provisional and Confirmed.
- An influencer paid on provisional numbers can be paid for revenue that later reverses.
- Whether miles are earned on the pre-discount basket or on the amount actually paid changes the true cost of every campaign, and it is still open. See decision 3 in the next tab.
Two correct answers, mid-window
| Moment | Provisional | Confirmed | Reversed | "How many redemptions" |
|---|---|---|---|---|
| Day 10, mid-window | 180 | 40 | 5 | 220 looks like the headline, but only 40 have settled. Both are correct, for different questions. |
| Day 40, window closed for this cohort | 0 | 210 | 15 | 210, the only number left, and lower than the day-10 headline. |
Figures are illustrative, not from a live campaign.
The latency budget
Third-party hop inside the budget. This hop is now the settled design, not an option: tier is always resolved live. Phase 1 never makes this call at all.
Merit stores no customer information and treats every user as anonymous. Tier-differentiated discounts resolve a member's tier live from Al Fursan's Accenture API at the moment a code is validated, inside a sub-500ms budget, per RF-02. Merit stores no member tier, no PII, and no Al Fursan member data of any kind, at any point. There is no cache and no data sync. Phase 1 does not use tier. Phase 2 does, and the only thing that bites there is latency, not data residency.
Why a nightly batch was not the cheaper answer
The obvious way to avoid a call inside the checkout path is to pull the membership base overnight and read it locally. That option was examined on 3 August 2026 and it fails for a reason that has nothing to do with privacy, which is worth stating because the privacy argument tends to crowd it out.
Merit only learns that a member exists when that member signs in to the store. If the programme holds a million members and only a fraction have ever signed in, Merit knows that fraction and nothing about the rest. A batch built on what Merit already holds would therefore answer for a minority of the base while appearing to answer for all of it. A batch built on the whole programme would require Al Fursan to hand over its full member list, which is a larger data-sharing decision than the one this initiative needs. The live lookup sidesteps the choice: the question is asked about exactly one member, at the moment that member is at checkout.
What the decision costs at campaign creation
Promo codes are a creation feature as much as a redemption one, and the two halves are not affected equally. Redemption gets better, because the tier read is always current and an upgrade applies to the very next basket. Creation gives something up, and it should be visible here rather than discovered during Phase 2.
Because Merit holds no copy of the membership base, the campaign creation screen cannot size an audience. Building a Gold tier offer, marketing will not see how many Gold members exist, what share of the base they represent, or how far a given set of restrictions would reach. Only Al Fursan holds the data that answers those questions. The accepted approach is the simpler one: define the code and its restrictions without member data in view, and let eligibility resolve per member at redemption. Audience sizing, if Al Fursan wants it, is a separate conversation about what data Al Fursan is willing to share, and it is not a dependency of Phase 2.
03 · the open decisions
Five business decisions, not an architecture choice
For this initiative the architecture is not contested. The business definitions are. These five items block Phase 1 from being scoped.
D5, D1, D2, and D3 all feed the Phase 1 scope freeze. D4 depends on D3 but is needed before contract, not before scoping.
Decision 1: what does "new customer" mean
Gating item 6. Owner: Al Fursan. Blocks CS-01.
| Option | What the member experiences | What it costs or requires | Can it make Phase 1? |
|---|---|---|---|
| Option A, new to the Al Fursan Storerecommended | A member with no prior order on this store qualifies, even if they are a long-time Al Fursan loyalty member elsewhere. | None. Merit can enforce this today from order history it already holds. No new integration. | Yes, ready today. |
| Option B, new to the Al Fursan loyalty programme | Only members newly enrolled in the loyalty programme qualify, regardless of store purchase history. | Requires Al Fursan to supply a membership join date. A new integration and a new data sharing question. | No, needs a new integration. |
| Verdict | Merit recommends Option A. | ||
Decision 2: acquisition offer, or one-per-member cap
Gating item 7. Owner: Al Fursan. Blocks CS-02.
Does "first purchase discount" mean a genuinely new customer, or the first time that member uses that code? These are different products. An acquisition offer is not the same thing as a one-per-member cap. The workshop transcript supports both readings, which is why it must be settled explicitly.
| Option | What the member experiences | What it costs or requires | Can it make Phase 1? |
|---|---|---|---|
| Option A, acquisition offer | Only members with zero prior orders on the store see the offer. A returning buyer never sees it, even on a code they have not used. | None new. This is exactly decision 1's customer-state check, CS-01. | Yes, if decision 1 lands. |
| Option B, one-per-member cap | Every member, new or returning, can try the code once. | None. Already covered by the rolling per-member limit RW-01. | Yes, ships regardless of decision 1. |
| Verdict | Al Fursan's call. If the intent is Option B, no new work is required beyond RW-01. | ||
Decision 3: miles on the pre-discount basket, or the amount paid
Gating item 8. Owner: Al Fursan and Merit commercial. Blocks ML-01.
| Option | What the member experiences | What it costs or requires | Can it make Phase 1? |
|---|---|---|---|
| Pre-discount basket value | The member is made whole; miles reflect what they would have earned without the discount. | The campaign costs Merit the discount plus miles on value nobody paid. | Yes, either answer can ship in Phase 1. |
| Amount actually paid | The member earns fewer miles on a promotional order, which may undercut the offer's appeal. | Cheaper for Merit, no miles issued on unpaid value. | Yes, either answer can ship in Phase 1. |
| Verdict | No recommendation. Neither answer is obviously correct, and this is a direct input to decision 4. | ||
SAR 400 basket, SAR 100 discount, an illustrative rate of 1 mile per SAR. This is not Al Fursan's real conversion rate, used only to size the gap. Pre-discount basis earns 400 miles. Amount-paid basis earns 300 miles. That is a delta of 100 miles per redemption between the two answers, illustrative.
Decision 4: who absorbs the discount
Gating item 3. Owner: Thamer Bamieh and Al Fursan.
The PRD currently states Merit absorbs the discount from its own share. That was written for Merit-owned marketplaces and has not been agreed for a tenant.
This cannot be priced until decision 3 lands, because the true cost of the discount depends on which basket value earns miles. Not a Phase 1 scoping blocker, but needed before contract.
Decision 5: how a household counts
Gating item 2. Owner: Al Fursan. Blocks RW-01.
Where a household holds one membership with family members underneath it, the per member limit can apply once to the household, or once to each family member. The rolling per member limit is Phase 1 scope, so this cannot be deferred. It has a second effect: the same answer decides whether a family member still counts as a new customer once the household has already purchased, which feeds straight back into decision 1.
| Option | What the member experiences | What it costs or requires | Can it make Phase 1? |
|---|---|---|---|
| Per-household | Family members share a single Saudi National Day discount between them. | None new beyond RW-01. Requires Al Fursan to identify household membership at validation. | Yes, if household identifiers are available. |
| Per-member | Every family member redeems independently, up to the full campaign discount each. | Multiplies the true campaign cost by household size. | Yes, simpler to enforce than the household option. |
| Verdict | No recommendation. Owned by Al Fursan. The answer also feeds decision 1, a family member's new or existing status. | ||
Non-blocking, listed so nothing looks hidden
Mirrors BRD section 8. These do not block Phase 1 scoping.
| Item | Owner | Needed by |
|---|---|---|
| Gating item 1 is closed, 3 August 2026. Merit no longer persists member tier, so the security and compliance approval that this item asked for is moot and needs no owner. Tier is resolved live from Al Fursan's Accenture API at validation time. TR-05 is retired. | Closed, no owner needed | Nothing. The remaining Phase 2 exposure is latency on the live call, the risk in the diagram above, not data storage. |
| Which tiers exist and the default discount per tier. | Al Fursan marketing | Phase 2 |
| Gating item 4, complete Al Fursan campaign list for the next two quarters. | Abdulelah, Al Fursan | Phase 2 scope close |
| Gating item 5, miles-to-cash conversion basis for miles-priced baskets. Blocks MI-02. | Merit engineering and Al Fursan finance | Phase 1, miles-priced baskets only |
| Whether a code should be usable on a first purchase only, beyond decision 2, as raised for the influencer scenario. | Al Fursan | Phase 3 |
| Gating item 9, treatment of a partial return. Blocks ML-02. | Al Fursan | Phase 2 |
| Gating item 10, whether influencer rewards are paid on provisional or confirmed redemptions. Blocks ML-06. | Al Fursan marketing | Phase 3 |
04 · the scope
Six epics, following the PRD's own structure
What Al Fursan is actually buying, grouped the way the PRD groups it: a user story, the requirement IDs it carries, which phase it ships in, who owns it, and the trade-off where one exists.
Code creation and management
As a LiveOps operator, I want to create a multi-use campaign or bulk-generate unique single-use codes, so I can launch a promotion without engineering involvement.
Create a shared code or bulk-generate up to 100,000 unique codes, and pause or end a live campaign, with a full change log. No engineering needed.
- owner
- Merit build
- trade-off
- Single-use batches cap at 100,000 codes per generation, CM-02.
Redemption at checkout
As a consumer, I want to enter a promo code at checkout and see the discount applied within 500ms, so I know immediately whether my code worked.
A code box at checkout, the discount shown instantly as its own line, one code per order, answered in under half a second.
- owner
- Merit build, critical path
- trade-off
- A 15-minute soft hold on an abandoned checkout, RF-04 and RF-05, trades a small window of held capacity for never blocking a genuine customer mid-checkout.
Condition enforcement
As a consumer, I want a clear reason when my code is rejected, so I know whether to try again or give up.
The gate sequence that decides whether a code applies, scoped to this store, with a clear rejection reason and new-versus-existing targeting.
- owner
- Merit build, blocked on decisions 1, 2, and 5
- trade-off
- Settled 3 August 2026: tier is resolved live from Al Fursan's Accenture API, never cached. Merit accepts the third-party hop inside the 500ms budget in exchange for storing no member tier and no PII at all. Caching is not a fallback and is not on the table. The lookup is keyed on the Al Fursan member ID, which is the anchor attribute both systems refer to a member by. It is constant from the day the profile is created, whereas email and phone number change across a membership lifetime and cannot carry that role.
Settlement and the provisional window
As a finance analyst, I want a redemption to stay Provisional until the 30-day miles window closes, so a campaign's cost is never finalised on numbers that can still reverse.
A redemption stays provisional for 30 days and reverses cleanly if the order cancels, so campaign cost is never counted before it settles.
- owner
- Merit build, new, blocked on decision 3
- trade-off
- The rolling per-member window and the miles credit window are both 30 days, but they are different clocks and must not be conflated.
Reporting and attribution
As a Finance team member, I want discount cost and redemption counts split Provisional from Confirmed, so I can account for promo cost honestly in the P&L.
Provisional and confirmed counts kept separate, discount cost split new versus existing, and a visible reversal rate per campaign.
- owner
- Merit build
- trade-off
- A single blended redemption number is never shown; Provisional and Confirmed are always two figures, ML-03, which costs dashboard simplicity for reporting honesty.
Admin console
As an operator, I want one screen to create a campaign, watch it in a dashboard, and export single-use codes, so I never need engineering to run a promotion.
One screen to create a campaign, watch it live in a dashboard, and export single-use codes.
- owner
- Merit build
- trade-off
- None noted. Tier rule fields arrive in Phase 2, member binding and attribution tag fields in Phase 3.
The condition ladder
Every code drops through these gates from the top. The first gate it fails decides the message the shopper sees, and the gates below it never run. For Saudi National Day only the Phase 1 gates are switched on. The greyed gates arrive in a later phase.
- Code exists and is active Fails when the code is unknown, or it has been paused or ended. Phase 1
- Inside its validity window Fails when the code has expired or has not started yet. Phase 1
- Belongs to this store Fails when the code was made for a different storefront. TN-01 Phase 1
- Reserved member matches, where the code is member-bound Fails when a bound code is presented by anyone else. VC-02 Phase 3
- Total usage cap not reached Fails when the code has been fully used up across all shoppers. Phase 1
- Within the shopper's per-member limit Fails when the shopper already used this code inside the rolling window. RW-01RW-02 Phase 1
- The shopper's tier has a discount on this code Fails when the code sets no discount for the shopper's loyalty tier. TR-03 Phase 2
- Matches the new or existing customer setting Fails when a new-only or existing-only code meets the wrong shopper. This gate is decisions 1 and 2. CS-01CS-02CS-03 Phase 1
- Marketplace scope matches Fails when the code is not valid in this marketplace. A baseline gate, not exercised by a single-store tenant. Phase 1
- Cart meets the minimum value Fails when the basket is below the code's minimum. Phase 1
- At least one item is in scope Fails when nothing in the cart qualifies for the code's category or product scope. Phase 2
The phase map
| Epic | Phase 1 | Phase 2 | Phase 3 |
|---|---|---|---|
| Code creation and management | CM-01 to CM-07 | — | VC-01 to VC-04 |
| Redemption at checkout | RF-01 to RF-08 | — | — |
| Condition enforcement | CE-01 to CE-05, TN-01, TN-02, RW-01, RW-02, CS-01 to CS-08 | TR-01 to TR-04, CS-09, category and product scope, per-campaign stacking toggle. TR-05 retired, nothing is cached. | VC-01, VC-02, member binding rung |
| Settlement and the provisional window | ML-01 to ML-07 | — | — |
| Reporting and attribution | FR-01 to FR-04, CS-07, CS-08, ML-03, ML-04, ML-06 | AT-02, CS-09 | AT-01, AT-02 |
| Admin console | Section 8.1 to 8.4, baseline fields | Tier rule table, plus the per-campaign stacking toggle on the campaign form, off by default | Member binding, attribution tag |
The eight systems, for engineering readers
Phase 1 does not need tier resolution or member binding. The live call to Al Fursan's Accenture API arrives in Phase 2, alongside category and product scoping and the per-campaign stacking toggle; member binding and bulk voucher generation arrive in Phase 3. No phase introduces a Merit-side store of member tier or PII. The Phase 1 machine is smaller than the full diagram shown next.
05 · the build
One member, one code, thirty days to know
A single Al Fursan member applies SNDAY25 to a SAR 400 basket. These are illustrative round figures, roughly a median store basket, and the member ID shown is a placeholder in the real format. It is not a real member.
Full text description of every step
When something breaks
Pick a scenario. The walkthrough replays on the same diagram with that component in the broken state, and the narration changes to the degraded path.
The three phases
Capability accumulates. Each phase keeps everything the phase before it shipped and adds the next layer. Phase 1 must land before Saudi National Day. Step through to see what each phase unlocks and what it still cannot do.
Phase 2 now carries a basic per-campaign promo code stacking toggle, added 3 August 2026. It is a single switch on a campaign, off by default, and a campaign has to opt in. That is the whole of it.
It is deliberately not the full stacking capability. Stacking groups, precedence and priority rules between competing codes, and the A/B testing framework are a much larger piece of work and stay deferred to a separate 2027 document, PRD_Promo_Engine_V2_Stacking_AB.md. The two should not be quoted, scoped, or estimated as if they were the same thing.
Phase 1 cannot be scoped until the blocking decisions are closed, and Saudi National Day does not move.
- Al Fursan closes decisions 1, 2, 3 and 5 this week.
- Confirm decision 4, the commercial treatment, once decision 3 lands.
- Brian resolves the P2 sequencing conflict in gating item 11, since Saudi National Day precedes the current window.