Pre-read for the technical deep dive
Two pages before the twenty. What the work is, who sets which number, why the Rewards Portal is waiting on Ecommerce Core rather than the other way round, and the six things that are still open and need an engineering answer.
Habeeb Rahman opened the 8 September call with the whole problem in two sentences, and everything below follows from it.
"In LiveOps, Marthino has a UI where I can go ahead and edit that and configure that. But once the request is submitted, which system does it come to, and where does it get stored? We don't have that system as of today, and that is why this entire discussion came into picture."
The screen exists. The storage does not. So the near-term work is not a portal. It is a place to hold four commercial parameters, a write path for LiveOps, and a read path for everyone else.
Diagram 1. Four parameters, not three. The tenant revenue split joins discount, markup and transaction fee. Read is open to the consuming systems, write is LiveOps only, and inside LiveOps only Finance and certain roles. The Core does not model those roles. The Rewards Portal keeps its own copy and serves its API clients from it, so there is no runtime call into the Core.
A platform-level answer would have needed roughly 300 pre-configured promo codes. Per tenant, per product removes all of them. The discounts in force today already sit in a spreadsheet held by the Online Catalogue sync team, so loading them is a migration task, not a discovery task.
The name says portal. The thing anybody is waiting on has no screens at all.
Diagram 2. Phase 0 is what unblocks the Rewards Portal and Jahez. Brian's commitment, in writing: "we can definitely set this without an interface for now to make it quicker and not be a blocker, the interface can be created later if needed." Phase 1 is real work Merit intends to do, and it is no longer work somebody else is waiting on.
It is not a new product. It is the Seller Portal codebase running a second workflow, backend and frontend, confirmed on 4 September. What is separate is the user experience and the data, not the system. A seller who does both gets a switch at the top, and the data stays apart on either side of that switch. Roughly half of the physical Seller Portal is shipping, packing, carriers and returns, and none of it applies here.
This is the part that gets rebuilt wrong, because the first draft of the PRD had it wrong too.
| Term | Who sets it | Where | Level |
|---|---|---|---|
| Discount | The merchant | This portal | Per product |
| Markup | Merit | Pricing engine, via LiveOps | Per product |
| Transaction fee | Merit | Pricing engine, via LiveOps | Per product, flat per transaction |
| Tenant revenue split | Merit | LiveOps | Per tenant, never shown to the client |
| Price and availability | The merchant | This portal | Per variant |
activation_fee | Merit | Pricing engine | Per variant, locked as A11 on 29 June |
Diagram 3. Brian's own example from the Doc, drawn. Note what the merchant never touches: markup, transaction fee and the tenant split are all Merit's, exactly as the physical Seller Portal already splits seller-side margin from marketplace-side markup.
Notes written before 8 September say the discount is set per variant,
because a USD 100 Amazon card and a USD 50 one carry different rates. That was corrected in the
call. Brian: "per tenant, per offer, offer as in per product." Habeeb: "Yes, per product,
correct." Recorded as DEC-0329. Price and availability stay per variant;
discount, markup and transaction fee are per product, and every denomination of
one card shares them. A per-variant discount implementation is the wrong build, and the older
note is still in circulation.
Store every term as a one-row tier table, not a bare number. Volume-tiered
slabs are deferred to a later release, and Panda's "8 percent between 250k and 500k dollars, 9
percent above it" is the live case. Two things carry into Phase 0 anyway, because both are cheap
now and a data migration later: SLB-EC-01, a flat 4 percent is a scheme with one tier
from zero to infinity, and SLB-EC-02, a nullable scheme_id where null
means flat. The settled approach: a scheme settles, it never reprices. Price and
tax are fixed at order time, and a crossed threshold becomes a credit note.
This is the piece of context that changes how the backlog reads.
Diagram 4. Al Fursan does not use the Rewards Portal. So the Rewards Portal does not block Al Fursan; Ecommerce Core blocks the Rewards Portal. The three areas came out of the Habeeb discussions and they sit inside the same migration backlog. First draft of that backlog: 13 September, running to several hundred items.
Named the single biggest blocker on 12 August and still open. The Rewards Portal does not need the marketplace concept, but it does need a global market, described as configuration rather than a build. Without it there are no multi-currency products at all.
80 percent done on 19 August and still 80 percent done. The remainder is front end. Nothing that routes to LiveOps can be approved until it lands, activation requests included.
New or removed product or brand, and changes to name, terms, description, denomination. Price and stock are explicitly out. Denominations are variants, and one event per change across the whole gift card catalogue will be noisy, so volume is a design input.
MGC stays, as a supplier. It remains the engine that fulfils gift cards because it is already connected to the aggregators and the providers. In the new world OMS triggers it per fulfilment rather than treating it as the system that fulfils orders. The retrofit matters now rather than after cutover, because Merit's digital gift card settings have to still work once MGC sits behind that boundary.
Both wrong answers are common, and they are wrong in opposite directions.
Diagram 5. Reading the two as one rule is how a team concludes either that gift cards are tax free, or that Merit owes 15 percent of face value.
What follows for the build. Every priced line carries a tax block per stream
(VAT-EC-01): rate, jurisdiction, taxable base, computed amount, and the party who
remits. It is written even when the amount is zero, because an absent line and a zero line are
different things on an invoice. The merchant's input stays one all-inclusive price
(VAT-SP-01) and Merit derives the breakdown. Never one blended number
(VAT-EC-02), because the two streams are remitted by different parties under
different registrations. Merit captures the seller's VAT registration status and TRN at
onboarding, and a tax class per product: a seller who is not registered has no VAT to charge, and
a blanket rate collects money nobody remits.
One rule to carry across from the marketplace side: VAT is calculated on the full pre-discount amount, not on the discounted amount. That fix is already in flight on marketplace with a sample invoice attached, and the same rule has to hold in the Core once the Rewards Portal runs through it.
Old world parity is a requirement, not a design choice. The
five fee names stay unchanged, because clients parse them today: handling_fee,
discount, processing_fee, activation_fee,
delivery_fee. Both FIXED and PERCENTAGE on any line.
Discount and markup are one signed field, never two, because they are the same adjustment in two
directions and cannot both apply at once.
Six items. Four of them need an engineering answer, which is why the session exists.
| Open item | Why it matters | Answer sits with |
|---|---|---|
| Does the tenant revenue split share the grain? | Discount, markup and transaction fee are per tenant, per product. The split is recorded as per tenant only. The slab discussion then put thresholds on it, which implies a product dimension nobody has stated. | Brian, Habeeb |
| What does the Core API have to expose, and by when? | The concrete ask on Muneeb's team: store and serve the four parameters per tenant, per product. Tracked as COM-0947, due 15 September. The existing discounts are already in a spreadsheet, so the data is a load. |
Muneeb and Khawar |
| What level does the pricing engine work at? | The largest unpriced item in the PRD. Two suppliers of the same card carry different discounts, which is offer level. The engine applies at category or product level today. Either it grows an offer level, or Merit accepts one set of terms per product. | Muneeb, Brian |
| Discount off face value, or a final price? | The old world only ever took a final price from the supplier and did not care how it was reached. The PRD says the merchant sets a discount. Both cannot be the input. | Muneeb, Brian, Habeeb |
| Can a merchant add a new product? | If a merchant can only edit and remove what Merit already carries, the supplier reference problem disappears entirely, because Merit created every product and holds every reference. | Habeeb, Brian |
| What does Phase 1 cost? | No estimate exists, for any of the three new items. The codebase is reused, so the number should be smaller than the name suggests. | Muneeb and Khawar |
It approves nothing, sets no dates, and resolves no handover recipient. It is an explanation. The one thing Brian wants out of it: that Muneeb can explain each piece to his own team without opening the PRD again.