# LivePrawn Customer Rewards Club — Implementation Plan

**Project:** Air Benih / Live Prawn (Magento 2)  
**Program name:** Customer Rewards Club  
**Tagline:** Buy fresh. Earn rewards. Save more every time.  
**Custom module (future):** `LivePrawn_CustomerRewards` — **foundation installed Phase 2 Batch 1 (2026-06-15)**  
**Document phase:** Phase 1 — Configuration in progress (order testing paused)  
**Magento root:** `/var/www/html/airbenih_stg`  
**Inspection date:** 2026-06-14  
**Magento mode:** `developer`  
**Requirements source:** `docs/Live Prawn Customer Rewards Club.pdf` (text provided 2026-06-14)

---

## 1. Scope

### 1.1 In scope

Public **customer-facing Magento site** for normal retail buyers purchasing small quantities (1kg, 2kg, family packs, festive bundles).

**Main goals:**

- Increase customer registration
- Increase first purchase conversion
- Increase repeat purchases
- Increase referral growth
- Increase birthday and anniversary reactivation
- Increase CNY/festive preorder sales
- Increase VIP customer retention

### 1.2 Explicitly out of scope

Do **not** include in this plan or implementation:

- Distributor Partner Program
- Restaurant Credit Terms Service
- Distributor Leaderboard
- Distributor Performance Bonus
- B2B restaurant/distributor portal

---

## 2. Requirements Reference (from product brief)

### 2.1 Recommended customer groups

Create or confirm:

| Group | Purpose |
|-------|---------|
| General / Guest | Default non-member pricing |
| Free Member | Member pricing, base rewards |
| Premium Member | Paid activation benefits |
| VIP Silver | RM1,000 lifetime spend |
| VIP Gold | RM3,000 lifetime spend |
| VIP Platinum | RM5,000 lifetime spend |

Customer groups are used for: member price access, premium member benefits, VIP tier benefits, coupon eligibility, special promotions, CNY price-lock access.

**Current store groups (inspection):** General (1), Wholesale (2), Retailer (3), Distribution (4). These B2B groups exist but are **out of scope** for the public retail program. New retail-focused groups must be created or mapped during Phase 1 configuration.

### 2.2 Customer pricing logic

Support on the public site:

- Non-member price
- Member price
- VIP promotional pricing where applicable
- CNY locked price where applicable

**Pricing reference (RM/kg):**

| SKU tier | Member price | Non-member price |
|----------|--------------|------------------|
| 40–45 | RM43 | RM48 |
| 30+ | RM50 | RM55 |
| 25+ | RM60 | RM65 |
| 20 | RM63 | RM70 |
| 15+ | RM75 | RM90 |

**Customer-facing message:** Join as a member and save up to RM15/kg.

### 2.3 Free Member program

Free Member registration is **free**.

Free Members receive:

- Member pricing
- 1.5% Prawn Points
- Referral program access
- Birthday voucher
- Anniversary voucher
- Access to selected member-only promotions
- Access to CNY Price Lock if enabled

### 2.4 Premium Member activation

**Virtual product:**

| Field | Value |
|-------|-------|
| Product name | Premium Member Activation |
| Price | RM100 |
| Type | Virtual Product |

After successful payment → customer becomes Premium Member.

Premium Member receives:

- 1kg Vannamei Welcome Pack
- RM20 Site Credit
- Member price access
- 1.5% Prawn Points
- Birthday voucher eligibility
- Anniversary voucher eligibility
- CNY Price Lock access

**Rules:**

- Welcome Pack redeemable with **first paid order only**
- Minimum first paid order to redeem Welcome Pack: **RM100**
- Welcome Pack subject to stock availability
- Welcome Pack is non-cash and non-transferable
- RM20 Site Credit can only be used during checkout
- RM20 Site Credit is non-cash and non-transferable

### 2.5 Prawn Points system

| Rule | Detail |
|------|--------|
| Earning | 1.5% back in Prawn Points on every **completed paid order** |
| Redemption | 100 points = RM1; usable as checkout discount |
| Issuance timing | Only when order is completed/paid |
| Exclusions | Cancelled, refunded, failed, pending, unpaid orders do not earn |
| Transfer | Non-cash, non-transferable |

**Configuration notes (Amasty Reward Points Lite):**

- Earning rate should represent 1.5% back
- Redemption allowed at checkout
- Prevent earning on orders fully paid by points if possible
- Points based on final paid product subtotal
- Shipping fee treatment should be configurable
- Points expiry: 90 or 180 days

### 2.6 Referral program — Refer A Friend

| Rule | Detail |
|------|--------|
| Mechanism | Existing customer receives referral code or link |
| Friend action | Friend registers using referral code/link |
| Referrer reward | RM10 Site Credit **only after** friend completes first paid order |
| Self-referral | Not allowed |
| Admin | Fake/suspicious referrals can be voided |
| Redemption | Non-cash; checkout only |

**Customer copy:** Refer a friend and get RM10 credit when they complete their first paid order.

**Operational rules:**

- Reward not issued on registration only
- Reward issued only after first successful paid order
- One referred customer triggers one referral reward only
- Refunded/cancelled first orders void the reward

### 2.7 Birthday voucher

| Tier | Amount |
|------|--------|
| Free Member | RM10 |
| Premium Member | RM10 |
| VIP Silver | RM15 |
| VIP Gold | RM20 |
| VIP Platinum | RM30 |

**Rules:** Issued during birthday month; expires end of birthday month or within 30 days; minimum spend applies; non-cash, non-transferable, not exchangeable for cash. **DOB is optional at registration** (to protect conversion) but **required before birthday voucher eligibility** — customer must save DOB in account/profile before a voucher can be issued.

### 2.8 Anniversary voucher

| Account/membership age | Amount |
|------------------------|--------|
| 6 months | RM10 |
| 12 months | RM20 |
| 24 months | RM30 |

**Rules:** Minimum spend required; expires within 30 days; non-cash, non-transferable; issued to active customers where possible.

### 2.9 VIP member tiers (lifetime spend)

**VIP Silver — RM1,000 lifetime spend:**

- Member prices
- 1.5% points
- Birthday voucher RM15
- Anniversary voucher RM10
- Member promos

**VIP Gold — RM3,000 lifetime spend:**

- All Silver benefits
- Birthday voucher RM20
- Anniversary voucher RM20
- Early promo access
- CNY early price lock access

**VIP Platinum — RM5,000 lifetime spend:**

- All Gold benefits
- Birthday voucher RM30
- Anniversary voucher RM30
- Free premium seafood reward worth up to RM100

**Rules:**

- Lifetime spend = completed paid orders only
- Cancelled, refunded, unpaid, failed, disputed orders excluded
- Auto-upgrade after qualifying order completion
- Downgrade not required unless fraud/refund abuse
- VIP reward recorded in reward ledger
- Platinum benefit must not be unlimited or vague

### 2.10 Review rewards (launch later if not easy to automate)

| Type | Credit |
|------|--------|
| Photo review | RM5 |
| Video review | RM10 |

**Rules:** After admin approval; one reward per order; genuine product-related review; non-cash, checkout only.

### 2.11 Group buy rewards

| Threshold | Reward |
|-----------|--------|
| 5kg combined | RM20 voucher |
| 10kg combined | Free local delivery |
| 20kg combined | RM100 voucher |

**Rules:** Same delivery address recommended; non-cash voucher; issued after completed order; free delivery for selected local coverage only; can use promotion rules or manual campaign first.

### 2.12 Family bundle deals

Create bundles: 1kg Weekend Pack, 2kg Family Pack, 3–5kg Reunion Pack, CNY Family Bundle, Hotpot Pack, BBQ Pack.

**Purpose:** Easier buying, higher AOV, encourage >1kg purchases, festive campaigns. Create as Magento bundle/simple products.

### 2.13 Double Points Day

2× Prawn Points on selected days (payday weekend, CNY preorder week, member day, festive campaigns, stock clearance).

**Rules:** Date-limited; based on completed paid orders; exclude selected/discounted products; configure via reward points/promotion logic if supported.

### 2.14 CNY Price Lock program

**Deposit products:**

| Deposit | Locks price for |
|---------|-----------------|
| RM30 | 1kg |
| RM50 | 2kg |
| RM100 | 5kg family bundle |

**Rules:** Deposit non-refundable; deductible from final order; customer chooses delivery/collection date; limited slots; size/stock subject to availability; full payment before delivery/collection; campaign closable when capacity full.

**If deposit deduction not supported:** Create deposit products and manage final redemption manually first.

### 2.15 Delivery date and checkout fields

**Recommended fields:**

- Preferred delivery date
- Preferred delivery time
- Delivery note
- CNY pickup/delivery date
- Seafood preparation note
- Gift message
- Referral code (if referral module not active)

### 2.16 Rewards ledger

**Future table:** `liveprawn_reward_ledger`

| Field | |
|-------|---|
| entity_id, customer_id, reward_type, transaction_type, amount, points, source_type, source_id, description, status, expires_at, created_at, updated_at | |

**Reward types:** prawn_points, site_credit, referral_credit, birthday_voucher, anniversary_voucher, premium_member_credit, welcome_pack, vip_reward, review_reward, group_buy_reward, cny_price_lock

**Statuses:** pending, approved, used, expired, void

**Rules:** Every reward recorded; admin inspects history; suspicious rewards voidable; used rewards traceable to order ID.

### 2.17 Future custom module — `LivePrawn_CustomerRewards`

**Path:** `app/code/LivePrawn/CustomerRewards/` (build later, after config gaps confirmed)

**Responsibilities:**

- Customer reward profiles
- Referral code generation
- Reward ledger tracking
- Premium Member Activation handling
- Premium Member group assignment
- RM20 Site Credit issuance
- 1kg Welcome Pack eligibility tracking
- Lifetime spend calculation
- VIP tier upgrades
- Birthday/anniversary voucher generation
- Integration with Amasty Reward Points and Amasty Affiliate where possible
- Admin reward views

**Constraints:** Do not modify Magento core files. Do not place business logic in theme files.

### 2.18 Suggested custom tables (document only — do not create yet)

**`liveprawn_customer_profile`:** entity_id, customer_id, membership_type, lifetime_spend, vip_tier, birthday, premium_activated_at, welcome_pack_status, welcome_pack_order_id, referral_code, created_at, updated_at

**`liveprawn_reward_ledger`:** (see §2.16)

**`liveprawn_referral`:** entity_id, referrer_customer_id, referred_customer_id, referral_code, status, first_paid_order_id, reward_ledger_id, created_at, updated_at

### 2.19 Future admin menu — Live Prawn Rewards

Submenus: Dashboard, Reward Ledger, Referrals, Customer Profiles, VIP Tier Report, Premium Members, Birthday Vouchers, Anniversary Vouchers, Settings

**Admin capabilities:** View/void rewards; view referrals; view VIP tier; manual reward adjustment with audit log; check welcome pack eligibility; check premium activation status.

### 2.20 Important business rules (global)

- Rewards are non-cash unless explicitly stated
- Redeemable only on the Magento site
- Points/credits used only during checkout
- Issued only after successful paid/completed orders
- Cancelled, refunded, failed, pending, unpaid orders excluded
- Referral credit only after friend's first paid order
- Welcome Pack: first paid order only; min RM100 for Premium
- Company may void suspicious rewards
- Company may amend campaign rules without prior notice
- CNY Price Lock subject to stock and delivery slot availability
- Credits, points, vouchers non-transferable
- Customer cannot cash out points, vouchers, or site credit

---

## 3. Inspection Findings (unchanged from Phase 1)

### 3.1 Magento version

| Item | Value |
|------|-------|
| Magento | **2.4.8-p4** (Community Edition) |
| CLI | `Magento CLI 2.4.8-p4` |
| PHP mode | `developer` |
| Theme | **Olegnax Athlete2** (`app/design/frontend/Olegnax/athlete2`) |
| Website | 1 store (`default` / Main Website) |
| Database | `airbenih_stg` |

### 3.2 Enabled modules (summary)

- **Total enabled:** ~451 modules
- **Disabled:** `Magento_TwoFactorAuth`, `Magento_AdminAdobeImsTwoFactorAuth`, `Olegnax_InfiniteScrollAmastyShopbyCompat`

**Non-Amasty extensions (enabled):** Olegnax Athlete2 stack, Magefan Blog, Magecomp Mobilelogin, Nwdthemes Revslider, HTCMage Countdown, PayPal Braintree.

**Local `app/code` copies:** `Amasty/Deliverydate`, Amasty Import suite.

### 3.3 Installed Amasty modules (enabled)

| Brief requirement | Installed module(s) | Status |
|-------------------|---------------------|--------|
| Reward Points Lite | `Amasty_RewardPointsLite`, `Amasty_Rewards` | Enabled |
| Affiliate | `Amasty_Affiliate` | Enabled |
| Special Promotions Lite | `Amasty_SpecialPromotionsLite`, `Amasty_Rules`, `Amasty_Conditions` | Enabled |
| Pre Order Lite | `Amasty_PreOrderLite`, `Amasty_Preorder` | Enabled |
| Delivery Date | `Amasty_Deliverydate`, `Amasty_CheckoutDeliveryDate` | Enabled |
| Order Attributes | `Amasty_Orderattr` | Enabled |
| One Step Checkout Pro | `Amasty_CheckoutProPackage`, `Amasty_CheckoutCore`, etc. | Enabled |
| Admin Actions Log | `Amasty_AdminActionsLog` | Enabled |
| Advanced Reports Lite | `Amasty_ReportsLite`, `Amasty_Reports` | Enabled |
| Export Orders | `Amasty_OrderExport`, `Amasty_OrderExportEntity` | Enabled |
| Mass Order Actions | `Amasty_Paction`, `Amasty_Oaction` | Enabled |

### 3.4 Current customer groups (live DB)

| ID | Code | Notes |
|----|------|-------|
| 0 | NOT LOGGED IN | Guest |
| 1 | General | Exists — may map to General/Guest retail |
| 2 | Wholesale | B2B — out of scope |
| 3 | Retailer | B2B — out of scope |
| 4 | Distribution | B2B — out of scope |

**Gap:** Free Member, Premium Member, VIP Silver/Gold/Platinum groups **do not exist yet**.

### 3.5 Current rewards, affiliate, promotions config

#### Amasty Reward Points (`amrewards/*`)

| Setting | Current value |
|---------|---------------|
| Enabled | Yes |
| Award on order status | `complete` |
| Spending rate | 1:1 (100 pts = RM1) ✓ matches brief |
| Min points to redeem | 100 |
| Expiration | Never (`expiration_behavior = 0`) — brief wants 90/180 days |
| Earning calculation | Before tax |
| Highlights | Enabled (product, category, cart, checkout, guest) |
| Show balance in account | No |
| Active earning rule | **Only rule ID 8 "test"** — 1.3 pts per RM100 (not 1.5%) |

#### Amasty Affiliate

- 1 program: "Pay per Sale" with $5 cart rule (affiliate commission model, not RM10 referral credit)
- Test affiliate account/data present
- Footer affiliate link enabled

#### Promotions

| Item | State |
|------|-------|
| Cart price rule | 1 — affiliate-linked |
| Catalog price rule | **"test" — 80% off category 3 — ACTIVE** (remove before launch) |

#### Pre-order, delivery, order attributes

- Modules enabled; **no admin config paths found** in `core_config_data`
- No custom order attributes defined

#### Checkout

- Amasty One Step Checkout Pro: 2-column layout configured
- Gift wrap, Google address autocomplete enabled

#### Products

- ~20 simple products (frozen tiger prawn SKUs)
- Member/non-member tier pricing **not yet configured** per brief reference prices

---

## Environment Safety Finding

**Inspection date:** 2026-06-14 (Phase 1, Step 8A)

The folder/database name **`airbenih_stg` is misleading**. This instance is **not** an isolated staging environment.

| Finding | Detail |
|---------|--------|
| Document root | **`/var/www/html/airbenih_stg/pub`** is the Apache document root for **`liveprawn.com`** (and **`airbenih.com`**) |
| Base URLs | **`https://liveprawn.com/`** (unsecure/secure base and base link URLs) |
| Separate staging URL | **None found** — only one Magento install under `/var/www/html/`; no `stg.*` / `staging.*` vhost |
| Database | `airbenih_stg` — same live instance (0 orders at inspection, but shared with public site) |
| Magento mode | `developer` (template hints enabled on storefront) |

**Do not create test orders unless explicitly approved.**

Test orders on this environment would affect:

- **Real inventory** (stock decrements on ship)
- **Sales reports**
- **Magento order/invoice/shipment emails** (`sales_email/order/enabled = 1`; SMTP active)
- **Amasty Prawn Points ledger** (`amasty_rewards_rewards` — earn/redeem is real)

Amasty earn/expire notification emails are disabled; Magento transactional order emails are not.

**Before testing order-lifecycle Prawn Points rewards**, choose one path:

1. **Preferred:** Create a **true staging clone** with a **separate URL and database** (e.g. `stg.liveprawn.com`), then run earn/redeem tests there first.
2. **If live test is explicitly approved:** Use **admin-only** create order with **Check / Money Order** (offline), **uncheck order confirmation email** at submit if offered, add a clear test comment (e.g. `PRAWN-POINTS-TEST-001`), verify points, then **cancel/credit memo**, restock, and adjust points balance as needed.

**Reference test customer (if approved):** `test-free-member+1@yourdomain.com` (customer ID 3, Free Member group 5).

---

## 4. Feature-by-Feature Module Mapping

| Feature | Requirement summary | Primary Amasty / Magento module | Config (admin) | Manual first | Custom `LivePrawn_CustomerRewards` | Gap / notes |
|---------|---------------------|---------------------------------|----------------|--------------|-------------------------------------|-------------|
| **Customer groups** | General/Guest, Free Member, Premium, VIP Silver/Gold/Platinum | Magento Customer Groups | Create/confirm groups; assign catalog/group prices | Map existing General (1) to retail guest/member flow | Auto-assign on premium purchase, VIP upgrade; Free Member on registration only if Magento config supports it (see Free Member row) | Wholesale/Retailer/Distribution exist but out of scope |
| **Member vs non-member pricing** | RM43–75 member / RM48–90 non-member by SKU | Magento Catalog (Group Price / Tier Price) | Set group prices per SKU for Free Member+ groups | — | Display "save up to RM15/kg" messaging | Tier prices not configured today |
| **Free Member registration** | Free; member pricing + base benefits | Magento Customer + Customer Group | **Step 1:** Create/confirm **Free Member** customer group. **Step 2:** Inspect whether Magento can assign new registered customers to Free Member via configuration (`Stores → Configuration → Customers → Customer Configuration → Create New Account Options → Default Group`). Document config path if yes. | Interim: manually move registrants to Free Member while inspecting | Profile + referral code on registration; **automatic Free Member assignment** if Magento default-group config is insufficient or unsafe | Free Member group does not exist yet; default-group assignment **not confirmed** |
| **Premium Member Activation** | RM100 virtual product → Premium | Magento Catalog (Virtual Product) | Create product SKU | — | Detect order, assign group, issue RM20 credit, welcome pack flag, ledger | Full automation needs custom module (Phase 3) |
| **Welcome Pack (1kg Vannamei)** | First paid order ≥ RM100 only | — | — | Manual fulfillment until automated | Track eligibility, validate first order min, ledger | No stock/eligibility tracking today |
| **RM20 Site Credit (Premium)** | Checkout-only, non-transferable | **Amasty Reward Points Lite** (only if RM20 can be issued/redeemed safely as checkout discount) **or** Magento cart price rule (single-use RM20 coupon) | On staging, test: (a) Amasty admin point grant of 2000 points (= RM20 at 100:1) with checkout-only redemption, or (b) one-time unique cart rule/coupon tied to customer | Manual single-use RM20 coupon issued by admin | **`LivePrawn_CustomerRewards` gap** if neither Amasty Rewards nor cart rules can enforce checkout-only, non-transferable, single-use RM20 site credit with audit trail | **Magento 2.4.8-p4 CE has no native store credit.** Do not assume Enterprise Customer Balance. Amasty Prawn Points may work only if RM20 maps cleanly to points; otherwise custom ledger + checkout credit required |
| **Prawn Points 1.5%** | 100 pts = RM1; completed orders only | **Amasty Reward Points Lite** | `moneyspent` rule: 1.5 pts per RM1 (or equivalent); order status = complete; expiry 90/180 days; min redeem 100 | — | Ledger sync for audit; Double Points Day multiplier if Amasty can't do 2× | Active rule is test 1.3/RM100; expiry not set |
| **Points checkout redemption** | Discount at checkout | **Amasty Reward Points Lite** | Spending rate 1:100; enable checkout block | — | — | Already enabled in highlights |
| **No earn on points-only orders** | Exclude if possible | **Amasty Reward Points Lite** | `amrewards/points/disable_reward` | — | — | Confirm on staging |
| **Refer A Friend (RM10)** | After friend's first paid order | **Amasty Affiliate** (test first) | Referral link/code; evaluate if fixed RM10 store credit fits | Manual referral tracking spreadsheet | Referral table, ledger, self-referral block, first-order trigger | Affiliate today is commission % not RM10 site credit |
| **Birthday vouchers** | RM10–30 by tier; birthday month | Magento Email + Cart Price Rules (+ core customer `dob` attribute) | **Step 1:** Confirm Magento DOB field is available (`Stores → Configuration → Customers → Customer Configuration → Name and Address Options → Show Date of Birth`). Keep DOB **optional at registration**. | Admin issues coupons monthly for customers with DOB on file | Cron: tier-aware voucher generation + ledger; **block issuance until DOB saved**; account prompt to add DOB before eligibility | DOB must **not** be required at signup; required only before first birthday voucher |
| **Anniversary vouchers** | 6/12/24 months; RM10/20/30 | Magento Cart Price Rules | Manual coupon campaigns | Export customers by created_at | Cron: membership-age vouchers + ledger | No anniversary automation |
| **VIP Silver/Gold/Platinum** | Lifetime spend RM1k/3k/5k | Magento Customer Groups | Create VIP groups | — | Lifetime spend calc, auto-upgrade, ledger, Platinum reward cap RM100 | No lifetime spend tracking |
| **VIP Platinum seafood reward** | Up to RM100; not unlimited | — | — | Manual voucher/product grant | One-time ledger entry + admin approval | Must cap at RM100 in custom logic |
| **Review rewards** | RM5 photo / RM10 video | Magento Reviews | — | Admin approves review → manual credit | Optional automation Phase 5+ | Launch later per brief |
| **Group buy rewards** | 5kg/10kg/20kg thresholds | **Amasty Special Promotions Lite** + cart rules | Cart rules on qty/weight conditions | Manual campaign | Optional weight aggregation | Weight-based rules need catalog weight data |
| **Family bundles** | Weekend/Family/Reunion/CNY/Hotpot/BBQ | Magento Catalog (Bundle/Simple) | Create bundle products | — | — | Catalog work only |
| **Double Points Day** | 2× on campaign days | **Amasty Reward Points Lite** OR **Special Promotions Lite** | Duplicate earning rule with 2× amount + date conditions | Manual points adjustment | Campaign scheduler if Amasty lacks date rules | Confirm Amasty rule date scheduling |
| **CNY Price Lock deposits** | RM30/50/100 deposit products | **Amasty Pre Order Lite** + Magento products | Deposit virtual/simple products; preorder labels | Manual deposit redemption reconciliation | Deposit tracking, slot limits, ledger | Deposit deduction likely **not** native — manual first |
| **Delivery date selection** | Preferred date/time | **Amasty Delivery Date** + **Checkout Delivery Date** | Enable module; configure date rules, holidays, lead time | — | — | Module installed, unconfigured |
| **Checkout custom fields** | Delivery note, prep note, gift message, CNY date, referral code | **Amasty Order Attributes** | Create attributes; assign to checkout step | — | Referral field if Affiliate UI insufficient | No order attributes defined |
| **One Step Checkout** | Faster conversion | **Amasty One Step Checkout Pro** | Layout already configured | — | Ensure rewards/credits blocks visible | Layout exists |
| **Member-only promotions** | Selected promos for members | **Amasty Special Promotions Lite** | Cart rules scoped to member customer groups | — | — | Test rule catalog 80% off must be removed |
| **Rewards ledger** | All credits/points/vouchers auditable | — | — | Spreadsheet interim | `liveprawn_reward_ledger` + admin grids | **Full gap** — Amasty history ≠ unified ledger |
| **Customer reward profile** | membership_type, vip_tier, referral_code, etc. | — | — | — | `liveprawn_customer_profile` | **Full gap** |
| **Referral tracking** | referrer/referred/first order/status | — | — | — | `liveprawn_referral` | **Full gap** unless Affiliate adapted |
| **Admin: Live Prawn Rewards menu** | Dashboard, ledger, referrals, VIP report, etc. | **Amasty Admin Actions Log** (audit) | — | Use native Amasty Rewards + Affiliate admin interim | Custom admin module | **Full gap** |
| **Audit trail for manual adjustments** | Admin changes logged | **Amasty Admin Actions Log** | Enable retention | — | Custom adjustment UI writes ledger + log | Partial via Amasty |

**Legend:** **Config** = Magento/Amasty admin configuration only. **Manual first** = operate by admin process before custom code. **Custom** = requires `LivePrawn_CustomerRewards`.

---

## 5. Settings to Configure (Phase 1 — no changes in this planning step)

### 5.1 Magento core

| Setting | Action |
|---------|--------|
| Customer groups | Create: Free Member, Premium Member, VIP Silver, VIP Gold, VIP Platinum |
| Group / tier prices | Set member vs non-member prices per SKU (40–45, 30+, 25+, 20, 15+) |
| Customer DOB attribute | Confirm core `dob` field is enabled/shown; keep **optional at registration**; require DOB save in account before birthday voucher eligibility |
| Free Member default group | Create/confirm Free Member group; inspect `Create New Account Options → Default Group` — document path if usable; defer auto-assignment to custom module if not |
| RM20 Site Credit (Premium) | Staging test only: Amasty Rewards (2000 pts) or single-use RM20 cart rule — confirm checkout-only behavior; otherwise flag custom-module gap |
| Virtual product | Create **Premium Member Activation** @ RM100 | **Done** — entity **95**, SKU `premium-member-activation`, enabled, Not Visible Individually |
| Deposit products | Create CNY Price Lock: RM30/RM50/RM100 | **Draft done** — entities **96–98**, **disabled**, Not Visible Individually |
| Bundle products | Create family packs (Weekend, Family, Reunion, CNY, Hotpot, BBQ) |
| Catalog rule "test" | **Disable/delete** (80% off — active today) |

### 5.2 Amasty Reward Points Lite

| Path / area | Target value |
|-------------|--------------|
| Enable program | Yes (already on) |
| Award on status | Complete/paid only |
| Earning rule | 1.5% — e.g. `moneyspent` 1.5 points per RM1 on subtotal |
| Spending rate | 100 points = RM1 |
| Min redeem | 100 points |
| Expiration | 90 or 180 days |
| Disable earn on points-paid orders | Yes if supported |
| Subtotal basis | Final paid product subtotal; confirm shipping exclusion |
| Remove test rule ID 8 | Replace with production 1.5% rule |
| Show balance in account | Enable |
| Double Points Day | Second rule or campaign-specific multiplier — confirm capability |

### 5.3 Amasty Affiliate (referral pilot)

| Area | Target |
|------|--------|
| Program type | Evaluate customer referral vs affiliate commission |
| Referrer reward | Fixed RM10 store credit (not %) |
| Trigger | Friend's first **paid completed** order only |
| Self-referral | Block |
| Customer-facing copy | "Refer a friend and get RM10 credit..." |

**Decision gate:** If Affiliate cannot do fixed RM10 after first friend order → build in `LivePrawn_CustomerRewards` Phase 4.

### 5.4 Amasty Special Promotions Lite

| Use case | Configuration |
|----------|---------------|
| Member-only coupons | Customer group conditions |
| First-order vouchers | Cart rules |
| Group buy thresholds | Qty/weight conditions |
| CNY / festive campaigns | Date-bounded rules |
| Birthday/anniversary (interim) | Manual unique coupon codes |

### 5.5 Amasty Pre Order Lite

| Use case | Configuration |
|----------|---------------|
| CNY preorder visibility | Product-level preorder flags |
| Deposit products | Likely simple/virtual products; confirm partial payment support |
| Final payment deduction | **Confirm gap** — manual reconciliation if unsupported |

### 5.6 Amasty Delivery Date + Order Attributes

| Item | Configuration |
|------|---------------|
| Preferred delivery date | Enable Checkout Delivery Date |
| Preferred delivery time | Order attribute (dropdown/text) |
| Delivery note | Order attribute |
| CNY pickup/delivery date | Order attribute |
| Seafood preparation note | Order attribute |
| Gift message | Order attribute or Magento gift message |
| Referral code | Order attribute (fallback if no referral UI) |

### 5.7 Amasty One Step Checkout Pro

| Item | Action |
|------|--------|
| Layout | Verify rewards block, order attributes, delivery date visible |
| Conversion | No change needed — already configured |

---

## Phase 1 Progress Checklist

Execution status as of **2026-06-14**:

| Step | Task | Status | Notes |
|------|------|--------|-------|
| 1 | Customer groups (Free Member, Premium, VIP Silver/Gold/Platinum) | **Completed** | IDs **5–9** created; tax class 3 (Retail Customer) |
| 2 | Default registration → Free Member | **Completed** | `customer/create_account/default_group = 5`; verified on test registrant |
| 3 | Member tier prices copied to reward groups | **Completed** | General tiers (20 SKUs) copied as-is to groups **5–9** (100 rows); Distribution (4) untouched |
| 4 | Prawn Points global + earning rule configuration | **Completed** | Rate **100:1**; expiry **180** days; rule **9** active; rule **8** inactive; groups **5–9** only |
| 5 | Catalog rule "test" (80% off) disabled | **Completed** | Rule ID 1 inactive; reindexed |
| 6 | Order-based Prawn Points testing (earn + redeem) | **Paused** | Awaiting **staging clone** or **explicit live-test approval** — see [Environment Safety Finding](#environment-safety-finding) |
| 7 | Batch 1 catalog foundations (Premium + CNY drafts) | **Completed** | 2026-06-14 — see [Phase 1 Batch 1](#phase-1-batch-1--catalog-foundations-completed-2026-06-14) |
| 8 | Batch 2 checkout fields + family bundle drafts | **Completed** | 2026-06-14 — see [Phase 1 Batch 2](#phase-1-batch-2--checkout-fields--family-bundle-drafts-completed-2026-06-14) |
| 9 | Phase 2 Batch 1 — `LivePrawn_CustomerRewards` foundation | **Completed** | 2026-06-15 — see [Phase 2 Batch 1](#phase-2-batch-1--custom-module-foundation-completed-2026-06-15) |
| 10 | Phase 2 stabilization checkpoint | **Completed** | 2026-06-15 — see [Phase 2 Stabilization](#phase-2-stabilization-checkpoint-completed-2026-06-15) |
| 11 | Phase 2 Batch 2 — Premium activation automation | **Completed** | 2026-06-15 — see [Phase 2 Batch 2](#phase-2-batch-2--premium-activation-automation-completed-2026-06-15) |
| 12 | Phase 2 Batch 3A — RM20 site credit redemption design | **Completed** | 2026-06-15 — inspection only — see [Batch 3A](#phase-2-batch-3a--rm20-site-credit-redemption-design-inspection-only--2026-06-15) |
| 13 | Phase 2 Batch 4A — Referral, birthday, anniversary design | **Completed** | 2026-06-15 — inspection only — see [Batch 4A](#phase-2-batch-4a--referral-birthday--anniversary-design-inspection-only--2026-06-15) |
| 14 | Phase 2 Batch 4B — Referral/birthday/anniversary backend foundation | **Completed** | 2026-06-15 — feature-flagged only — see [Batch 4B](#phase-2-batch-4b--referral-birthday--anniversary-backend-foundation-completed-2026-06-15) |
| 14b | Hotfix — Birthday/Anniversary admin pages | **Completed** | 2026-06-15 — see [Admin hotfix](#hotfix--birthdayanniversary-admin-pages-2026-06-15) |
| 15 | Phase 2 Checkpoint Audit | **Completed** | 2026-06-15 — see [Checkpoint Audit](#phase-2-checkpoint-audit--2026-06-15) |
| 16 | True staging clone plan | **Completed** | 2026-06-15 — planning only — see [Staging Setup Plan](live-prawn-staging-setup-plan.md) |
| 17 | True staging clone execution | **Blocked** | **Required before** order/checkout/reward testing — see [Staging Setup Plan](live-prawn-staging-setup-plan.md) |
| 18 | Phase 2 Batch 3B — site credit checkout collector | **Blocked** | **Must wait until staging exists** — see [Batch 3B gate](#batch-3b--checkout-collector-gate) |

**Do not proceed with Step 6 until true staging clone is executed and verified.**

---

## Phase 1 Batch 1 — Catalog Foundations (Completed 2026-06-14)

**Environment:** Live `liveprawn.com` instance (`/var/www/html/airbenih_stg`). No orders created. No checkout tests. No emails sent.

### Products created

| Entity ID | SKU | Name | Type | Price | Status | Visibility |
|-----------|-----|------|------|-------|--------|------------|
| **95** | `premium-member-activation` | Premium Member Activation | virtual | RM100 | **Enabled** | Not Visible Individually |
| **96** | `cny-price-lock-deposit-1kg` | CNY Price Lock Deposit - 1kg | virtual | RM30 | **Disabled** | Not Visible Individually |
| **97** | `cny-price-lock-deposit-2kg` | CNY Price Lock Deposit - 2kg | virtual | RM50 | **Disabled** | Not Visible Individually |
| **98** | `cny-price-lock-deposit-5kg-family` | CNY Price Lock Deposit - 5kg Family Bundle | virtual | RM100 | **Disabled** | Not Visible Individually |

**Shared settings:** Main Website (ID 1); **no categories** (not in Frozen/Live prawn categories); tax class **Taxable Goods (ID 2)**; virtual stock **In Stock**, manage stock **No**.

**Premium Member Activation only:** **Max Qty Allowed in Shopping Cart = 1** (`max_sale_qty = 1`, `use_config_max_sale_qty = 0`). Verified **salable** after stock reindex.

**Automation:** None yet. Premium upgrade, RM20 credit, and welcome pack eligibility remain **`LivePrawn_CustomerRewards` Phase 3** gaps.

### Prawn Points exclusion (rule ID 9)

| Setting | Value |
|---------|-------|
| Grant Points For Specific Products | **Yes** |
| Action | **Exclude** |
| SKU | `premium-member-activation` |

Amasty `moneyspent` earning checker supports this via `EarningChecker` + `SuitableItemChecker` (exclude SKU list).

**Not yet excluded:** CNY deposit SKUs (disabled drafts — not purchasable until enabled at campaign launch). Add to exclude list when enabling CNY products if deposits should not earn points.

### Indexing performed

| Indexer | Run? | Reason |
|---------|------|--------|
| `catalog_product_price` | **Yes** | New products added |
| `cataloginventory_stock` | **Yes** | Required for Premium product **salable** status (24-item backlog included new SKUs) |
| Full reindex | **No** | |
| Full cache flush | **No** | |

OpenSearch/catalog search reindex failed (no search cluster) — **not required** for Not Visible Individually products.

### Remaining gaps after Batch 1

| Gap | Notes |
|-----|-------|
| Premium activation workflow | Custom module Phase 3 — detect order, assign Premium group, RM20 credit, welcome pack flag |
| CNY deposit redemption / slot tracking | Manual first; custom module Phase 5 |
| Direct URL / CMS page for Premium Activation | Product not visible in catalog — needs CMS link or category when ready to sell publicly |
| CNY products launch | Enable status + campaign config when CNY window opens |
| Order-based Prawn Points test | Still **paused** — environment safety |
| Family bundle products | Draft placeholders created in Batch 2 — see [Phase 1 Batch 2](#phase-1-batch-2--checkout-fields--family-bundle-drafts-completed-2026-06-14) |
| Member vs brief reference pricing (RM43–75) | Tier prices copied as-is from General; brief alignment deferred |

**Do not proceed with Step 6 until true staging clone is executed and verified.**

---

## Phase 1 Batch 2 — Checkout Fields & Family Bundle Drafts (Completed 2026-06-14)

**Environment:** Live `liveprawn.com` instance (`/var/www/html/airbenih_stg`). No orders created. No checkout tests. No emails sent. No `setup:upgrade`, `di:compile`, static deploy, or full cache flush.

### A. Amasty Delivery Date inspection

| Area | Finding |
|------|---------|
| **Modules** | `Amasty_Deliverydate`, `Amasty_CheckoutDeliveryDate`, `Amasty_CheckoutCore` — all enabled |
| **Standalone Delivery Date (`amdeliverydate`)** | **Enabled** (default). Min interval **0 days** (same-day allowed). Max interval **unset**. No disabled weekdays beyond default. Same-day / next-day cutoffs **off**. |
| **Date field** | Optional (`required=0`) |
| **Time field** | **Enabled**, optional. **0 time intervals** in `amasty_amdeliverydate_tinterval` — no configured slots |
| **Comment field** | **Enabled**, optional (maps to delivery note on standalone module) |
| **Blackouts** | **0 holidays**, **0 delivery intervals** (`dinterval`) |
| **OSC integration (`amasty_checkout/delivery_date`)** | **`enabled` not set** (effectively off). Comment default **on** in module default only. **Delivery block not in layout builder** (`frontend_layout_config` has shipping_address, shipping_method, payment_method, summary only) |
| **One Step Checkout Pro** | Delivery date/time/comment **will not render** until OSC delivery date is enabled **and** block added to layout builder — no layout changes made in Batch 2 |

**Preferred delivery date:** Use Amasty Checkout Delivery Date when ready to enable (not duplicated as order attribute). **Preferred delivery time / delivery note:** Amasty OSC fields inactive; order attributes created below as interim fields.

### B. Amasty Order Attributes inspection (before creation)

| Item | Status |
|------|--------|
| Entity type | `amasty_checkout` (ID 9) |
| Existing attributes | **0** before Batch 2 |
| Supported input types | text, textarea, date, datetime, select, multiselect, boolean, radios, checkboxes, html, file |
| Checkout placement | Configurable per attribute (`checkout_step`); integrates with Amasty OSC via `LayoutProcessor` |
| Admin / order visibility | `is_visible_on_back`, grids, PDF, email flags supported |

### C. Order attributes created

All optional (`is_required=0`). Placement: **Below Shipping Methods** (`checkout_step=8`). Visible on front + admin unless noted.

| Attribute ID | Code | Label | Input | Required | Frontend visible | Notes |
|--------------|------|-------|-------|----------|------------------|-------|
| **194** | `preferred_delivery_time` | Preferred Delivery Time | select | No | Yes | Options: Morning, Afternoon, Evening |
| **195** | `delivery_note` | Delivery Note | textarea | No | Yes | Interim until OSC delivery comment enabled |
| **196** | `cny_pickup_delivery_date` | CNY Pickup / Delivery Date | date | No | **Hidden** (`is_hidden_from_customer=1`) | Activate for CNY campaign |
| **197** | `seafood_preparation_note` | Seafood Preparation Note | textarea | No | Yes | |
| **198** | `gift_message` | Gift Message | textarea | No | Yes | |
| **199** | `referral_code_fallback` | Referral Code | text | No | Yes | Temporary until `LivePrawn_CustomerRewards` referral flow |

**Referral:** Amasty Affiliate enabled (commission / URL cookie model) — **not** RM10 friend referral credit at checkout. Fallback field created.

**Skipped:** None — all six attributes created successfully.

### D. Family bundle recommendation & draft products

**Recommendation:** Production family packs should be **Magento bundle** products (fixed/optional child simple prawn SKUs, bundle-level campaign price, stock from components). **Grouped** suits side-by-side SKU choice, not mixed-weight packs. **Configurable** is for attribute variants. **Simple** used only for safe disabled drafts.

| Entity ID | SKU | Name | Type | Price | Status | Visibility |
|-----------|-----|------|------|-------|--------|------------|
| **99** | `draft-weekend-pack-1kg` | 1kg Weekend Pack (Draft) | simple | RM0.01 placeholder | **Disabled** | Not Visible Individually |
| **100** | `draft-family-pack-2kg` | 2kg Family Pack (Draft) | simple | RM0.01 placeholder | **Disabled** | Not Visible Individually |
| **101** | `draft-reunion-pack-3-5kg` | 3-5kg Reunion Pack (Draft) | simple | RM0.01 placeholder | **Disabled** | Not Visible Individually |
| **102** | `draft-cny-family-bundle` | CNY Family Bundle (Draft) | simple | RM0.01 placeholder | **Disabled** | Not Visible Individually |
| **103** | `draft-hotpot-pack` | Hotpot Pack (Draft) | simple | RM0.01 placeholder | **Disabled** | Not Visible Individually |
| **104** | `draft-bbq-pack` | BBQ Pack (Draft) | simple | RM0.01 placeholder | **Disabled** | Not Visible Individually |

**Shared:** Main Website; **no categories**; tax class Taxable Goods (2); not salable (disabled). Replace with bundle SKUs when composition/pricing finalized.

### E. Verification (Batch 2)

| Check | Result |
|-------|--------|
| Delivery Date status | Documented above — standalone on, OSC block off, no time slots |
| Order attributes | **6 created**, 0 errors |
| Checkout cache / static deploy | **Not required** (developer mode); browser refresh sufficient |
| Orders created | **0** |
| setup:upgrade / di:compile / static deploy / full cache flush | **Not run** |

### Remaining gaps after Batch 2

| Gap | Notes |
|-----|-------|
| Enable OSC delivery date block | Admin: `amasty_checkout/delivery_date/enabled=Yes`, configure available days/hours, add block to layout builder |
| Configure Amasty time intervals | Admin: Delivery Date → Time Intervals, or OSC available hours — may reduce need for `preferred_delivery_time` select |
| Dedupe delivery note | When OSC delivery comment live, consider hiding `delivery_note` order attribute to avoid duplicate fields |
| CNY pickup date visibility | Unhide `cny_pickup_delivery_date` when CNY campaign opens |
| Referral code processing | `LivePrawn_CustomerRewards` Phase 3 — read `referral_code_fallback`, issue RM10 credit |
| Family bundle final catalog | Convert drafts to bundle products with child SKUs, tier prices, categories, images |
| Order-based checkout field test | **Paused** — environment safety |
| Premium activation workflow | Still Phase 3 custom module |

---

## Phase 2 Batch 1 — Custom Module Foundation (Completed 2026-06-15)

**Environment:** Live `liveprawn.com` instance (`/var/www/html/airbenih_stg`). No orders created. No checkout tests. No emails sent. No `di:compile`, static deploy, or full cache flush.

### Module

| Item | Value |
|------|-------|
| Module | `LivePrawn_CustomerRewards` |
| Path | `app/code/LivePrawn/CustomerRewards/` |
| Status | **Enabled** |
| Config | `liveprawn_customerrewards/general/enabled = 1` (default) |

### Database tables (declarative schema)

| Table | Purpose |
|-------|---------|
| `liveprawn_customer_profile` | Customer reward profile (membership, VIP tier, referral code, welcome pack status) |
| `liveprawn_reward_ledger` | Reward ledger (no auto-issuance in this batch) |
| `liveprawn_referral` | Referral tracking (no auto-processing in this batch) |

Schema applied via `setup:db-schema:upgrade` (full `setup:upgrade` blocked by OpenSearch cluster validation — pre-existing environment issue).

### Admin menu — Live Prawn Rewards

| Submenu | Route / action | Batch 1 status |
|---------|----------------|----------------|
| Dashboard | `liveprawn_rewards/dashboard/index` | Foundation installed message |
| Reward Ledger | `liveprawn_rewards/rewardledger/index` | Placeholder page |
| Referrals | `liveprawn_rewards/referrals/index` | Placeholder page |
| Customer Profiles | `liveprawn_rewards/customerprofiles/index` | Placeholder page |
| VIP Tier Report | `liveprawn_rewards/viptierreport/index` | Placeholder page |
| Premium Members | `liveprawn_rewards/premiummembers/index` | Placeholder page |
| Birthday Vouchers | `liveprawn_rewards/birthdayvouchers/index` | Placeholder page |
| Anniversary Vouchers | `liveprawn_rewards/anniversaryvouchers/index` | Placeholder page |
| Settings | Stores → Live Prawn → Customer Rewards | Enabled toggle only |

ACL resources registered under `LivePrawn_CustomerRewards::menu`.

### Customer registration observer

- **Event:** `customer_register_success`
- **Observer:** `CreateCustomerProfileOnRegister`
- **Behavior:** Creates `liveprawn_customer_profile` if missing; generates unique referral code `LP{customer_id}{4-char suffix}`; sets `membership_type=free`, `vip_tier=none`, `lifetime_spend=0`, `welcome_pack_status=not_eligible`
- **Does not:** change customer group, issue points/credits/vouchers, or alter checkout

### Test customer backfill (customer ID 3)

Existing test customer `test-free-member+1@yourdomain.com` (Free Member, group **5**) backfilled via bootstrap (no new customer registration, no order):

| Field | Value |
|-------|-------|
| Profile entity_id | **1** |
| customer_id | **3** |
| membership_type | free |
| vip_tier | none |
| lifetime_spend | 0.00 |
| welcome_pack_status | not_eligible |
| referral_code | **LP3E627** |
| Customer group | **5** (unchanged) |

### Verification (Batch 1)

| Check | Result |
|-------|--------|
| Module enabled | **Yes** |
| Tables exist | **Yes** (3 tables) |
| Admin menu / routes | **Registered** (verify in Admin UI after ACL role refresh) |
| Profile for customer 3 | **Yes** |
| Orders created | **0** |
| Reward ledger auto-entries | **0** |
| Referral auto-entries | **0** |
| Customer groups changed | **No** |
| setup:di:compile | **Not run** |
| Static deploy | **Not run** |
| Full cache flush | **Not run** (config + block_html cleaned only) |

### Not implemented (deferred)

| Feature | Target phase |
|---------|--------------|
| Premium Member activation automation | Phase 3 |
| RM20 site credit issuance | Phase 3 |
| Welcome pack logic | Phase 3 |
| VIP tier upgrade automation | Phase 4 |
| Referral RM10 credit processing | Phase 4 |
| Birthday / anniversary voucher cron | Phase 5 |
| Admin UI grids (full CRUD) | Phase 2+ follow-up |
| Checkout integration / reward redemption | Phase 3+ |

### Setup notes

- `module:enable` failed clearing `generated/code` (directory permissions); module enabled via `app/etc/config.php`.
- `setup:upgrade` failed OpenSearch validation; **`setup:db-schema:upgrade` succeeded** for schema creation.

---

## Phase 2 Stabilization Checkpoint (Completed 2026-06-15)

**Goal:** Fix runtime/permission issues from Batch 1 install before adding Premium activation automation. No new reward features, orders, group changes, or config changes.

### Issues found at install

| Issue | Root cause |
|-------|------------|
| `setup:upgrade` failed | OpenSearch cluster validation — `localhost:9200` unreachable (connection refused) |
| `module:enable` failed | Could not delete/recreate `generated/code` subdirs (mixed `root`/`dev` ownership) |
| Admin `ReflectionException` | Missing `Amasty\Rolepermissions\Model\Authorization\GetCurrentUserFromContext\Interceptor` — could not auto-generate due to write permissions |
| Mixed cache ownership | `var/cache/mage--*` subdirs owned by `root` after CLI runs as root |

### Fixes applied (2026-06-15)

| Action | Detail |
|--------|--------|
| Ownership | `chown -R dev:www-data` on `generated/code`, `generated/metadata`, `var/cache`, `var/page_cache`, `var/view_preprocessed` |
| Permissions | `chmod -R g+w` + setgid (`g+s`) on directories so `dev` and `www-data` share write access |
| Interceptor | Auto-generated on first adminhtml bootstrap after permission fix |
| Cache | `cache:clean config block_html` only (no full flush) |

**Not run:** `setup:upgrade`, `setup:di:compile`, static deploy, full cache flush, OpenSearch config changes.

### Verification after stabilization

| Check | Result |
|-------|--------|
| `module:status LivePrawn_CustomerRewards` | **Enabled** |
| `setup:db:status` | **All modules are up to date** |
| `dev` write to `generated/code` | **OK** |
| `www-data` write to `generated/code` + `var/cache` | **OK** |
| Adminhtml `ReflectionException` | **Resolved** — interceptor file exists |
| Live Prawn Rewards admin controllers (bootstrap) | **Dashboard, Reward Ledger, Referrals, Customer Profiles instantiate OK** |
| ProfileCreator in adminhtml area | **OK** (customer 3 profile readable) |

### OpenSearch / catalog search status

| Setting | Value |
|---------|-------|
| Engine (`catalog/search/engine`) | **opensearch** |
| Host | `localhost:9200` |
| Auth | Enabled (`admin` user) |
| Cluster health | **Unreachable** (connection refused on port 9200) |
| `catalogsearch_fulltext` indexer | **Reindex required** (6 in backlog, schedule idle) |

**Impact:** Full `setup:upgrade` remains blocked by OpenSearch validation. **Catalog search index is stale/broken** until OpenSearch is restored or engine is changed — this does **not** block admin reward module work or hidden-SKU products, but **does** affect storefront catalog search. **No OpenSearch config changed** in this checkpoint.

### Is `setup:upgrade` safe to defer?

**Yes, for now.** `setup:db:status` reports all DB schema/data up to date including `LivePrawn_CustomerRewards` tables. Deferring full `setup:upgrade` is acceptable while:

- No new modules or data patches are pending
- Schema was applied via `setup:db-schema:upgrade`
- OpenSearch cluster is not running on this host

Run full `setup:upgrade` only after OpenSearch is restored **or** when intentionally changing search engine config (requires separate approval).

### Proceed to Phase 2 Batch 2?

**Yes — safe to proceed** with Premium activation automation (Phase 3 / Batch 2 scope) provided:

- Admin changes are tested via bootstrap or admin UI (no checkout orders on live)
- OpenSearch fix is tracked separately if catalog search reindex is needed before go-live
- CLI commands continue as `dev` user (not root) to avoid permission regression

---

## Phase 2 Batch 2 — Premium Activation Automation (Completed 2026-06-15)

**Environment:** Live `liveprawn.com`. No orders created. No checkout tests. No emails. Ledger-only — no checkout redemption yet.

### Trigger

| Item | Value |
|------|-------|
| Event | `sales_order_save_after` |
| Observer | `ProcessPremiumActivationOnOrderComplete` |
| Conditions | Order **state** transitions to `complete` (not already complete); contains SKU `premium-member-activation`; registered customer; not cancelled/refunded path |

### Actions on qualifying complete order

| Step | Action |
|------|--------|
| 1 | Upgrade customer group to **Premium Member (6)** if current group ID **< 6** (never downgrade Premium/VIP) |
| 2 | Update `liveprawn_customer_profile`: `membership_type=premium`, `premium_activated_at=now` (if unset), `welcome_pack_status=eligible`, `vip_tier` unchanged |
| 3 | Ledger: `premium_member_credit` — RM20, `transaction_type=earn`, `status=**pending**` (not checkout-redeemable until Batch 3) |
| 4 | Ledger: `welcome_pack` — eligibility flag, `status=**approved**`, `amount/points=null` |

### Idempotency

| Guard | Mechanism |
|-------|-----------|
| Same order processed twice | Skip if `orig state === complete` |
| Duplicate ledger rows | `findBySourceAndRewardType(customer_id, order, increment_id, reward_type)` before insert |
| Already Premium/VIP group | Skip group change when `currentGroupId >= premiumGroupId (6)` |
| Guest orders | Skipped (logged) |

### Admin config (Stores → Live Prawn → Customer Rewards → Premium Member Activation)

| Setting | Default |
|---------|---------|
| Enable Premium Activation Automation | Yes |
| Premium Activation SKU | `premium-member-activation` |
| Premium Member Group ID | **6** |
| Premium Site Credit Amount (RM) | **20** |
| Welcome Pack Minimum First Paid Order (RM) | **100** (for future redemption) |

### Premium Members admin page

Shows counts: premium profiles, pending RM20 ledger entries, welcome-pack-eligible profiles (placeholder grid deferred).

### Verification (Batch 2)

| Check | Result |
|-------|--------|
| Orders in DB | **0** |
| Ledger entries created | **0** |
| Customer groups changed | **No** (definitions intact; customer 3 still group 5) |
| `module:status` | **Enabled** |
| `setup:db:status` | **All modules up to date** |
| Schema changes | **None** (existing tables sufficient) |

### Remaining gaps after Batch 2

| Gap | Target |
|-----|--------|
| Checkout redemption of RM20 site credit | Phase 2 Batch 3 |
| Welcome pack redemption on first paid order ≥ RM100 | Phase 2 Batch 3+ |
| Live order test (Premium Activation purchase → complete) | **Paused** — staging clone or explicit live approval |
| Admin full ledger/profile grids | Later batch |
| Amasty Prawn Points / cart rule integration for RM20 | Evaluate in Batch 3 |

---

## Phase 2 Batch 3A — RM20 Site Credit Redemption Design (Inspection Only — 2026-06-15)

**Environment:** Live `liveprawn.com`. **No implementation.** No checkout changes. No orders. No config changes. No cache flush.

### Inspection summary

#### 1. Amasty Reward Points — manual grant & RM20 equivalence

| Item | Finding |
|------|---------|
| Admin manual points | **Supported** — `RewardsProvider::addRewardPoints()` / Admin Point Change action (`amrewards/general/adminaction`) |
| Rate | **100 points = RM1** (`amrewards/points/rate = 100`) → **2000 points = RM20** |
| Min redeem | **100 points** (`minimum_reward = 100`) — RM20 redemption meets minimum |
| Checkout redemption | **Enabled** — `Amasty\Rewards\Model\Quote\Collector\Points` registered in `etc/sales.xml` (`sort_order=310`, after sales-rule discount at 300) |
| OSC UI | Checkout highlight **on** (`amrewards/highlight/checkout = 1`) |
| Expiration | **180 days** on granted points (same as program default) |
| `disable_reward=1` | Means **do not earn points on orders paid with points** — not a redemption block |
| Balance label | **Prawn Points** — no separate “site credit” label |
| Ledger sync | Amasty history in `amasty_rewards_rewards` — **separate** from `liveprawn_reward_ledger` |

#### 2. Using Amasty points for RM20 Premium Credit — safe or confusing?

**Technically feasible, business-wise confusing.**

| Pro | Con |
|-----|-----|
| Checkout discount already works | Merges promotional **site credit** with loyalty **Prawn Points** in one pool |
| 2000 pts = RM20 at current rate | Customer UI shows “Prawn Points”, not “Premium RM20 credit” |
| Admin can grant via API/provider | 180-day expiry applies unless custom expiration handling |
| | Dual audit: `liveprawn_reward_ledger` (pending) vs Amasty balance — sync required |
| | Customer could spend welcome RM20 on **any** cart meeting Amasty rules, not necessarily “first seafood order” intent |
| | Future referral/birthday credits would all look like points — hard to enforce per-type rules |

#### 3. Magento cart price rule — one-time RM20 coupon

| Item | Finding |
|------|---------|
| Fixed RM20 off | **Supported** via Cart Price Rule (fixed amount discount) |
| One-time per customer | **Supported** — `uses_per_customer = 1` + unique coupon code |
| Customer-specific | **Partial** — can use customer conditions (email/group) or generate unique coupon per customer via code |
| Auto-apply at checkout | **Not native** — requires custom plugin or customer entering code |
| Safety | Coupon codes can leak/share; stacking with member tier prices and Prawn Points needs explicit rules |
| Ledger link | **No native link** — custom glue needed to mark `liveprawn_reward_ledger` as used |
| Audit | `salesrule_coupon_usage` tracks usage but not unified with Live Prawn ledger |

#### 4. Native Magento store credit (Open Source)

| Item | Finding |
|------|---------|
| Magento Enterprise Customer Balance | **Not present** — CE 2.4.8-p4, no `Magento_CustomerBalance` module |
| PayPal BraintreeCustomerBalance | Module enabled but **Braintree-specific**, not a general site-credit wallet |
| **Conclusion** | **No native store credit** on this instance — custom or Amasty/coupon workaround required |

#### 5. Existing checkout totals collectors & Amasty redemption flow

**Quote totals order (relevant):**

| Sort | Collector | Module |
|------|-----------|--------|
| 300 | `Magento\SalesRule\Model\Quote\Discount` | Cart price rules |
| 310 | `Amasty\Rewards\Model\Quote\Collector\Points` | Prawn Points spending |
| 400 | Shipping discount | Sales rule |

**Amasty flow:** Customer applies points on cart/checkout → `points_spent` stored on quote (`EntityInterface::POINTS_SPENT`) → collector converts points to discount via `Calculation\Discount` and `ToMoney` converter → deducts on order placement via rewards provider.

**Amasty One Step Checkout Pro** is active; rewards highlight enabled for checkout — points UI slot exists as reference for future site-credit UI placement.

#### 6. Custom `LivePrawn_CustomerRewards` totals collector — feasibility

**Feasible and aligns with existing ledger architecture.**

Proposed new files (Batch 3B — not built yet):

| File / area | Purpose |
|-------------|---------|
| `etc/sales.xml` | Register `Model/Quote/Total/SiteCredit` collector (`sort_order` ~305–315, document stacking vs points) |
| `Model/Credit/BalanceProvider.php` | Sum `approved` `premium_member_credit` earn rows minus used/spent |
| `Model/Credit/RedemptionManager.php` | Apply credit to quote; mark ledger `used`; idempotency |
| `Model/Quote/Total/SiteCredit.php` | `AbstractTotal` — apply discount up to min(subtotal, available credit) |
| `etc/extension_attributes.xml` | Quote fields: `liveprawn_site_credit_applied`, `liveprawn_site_credit_ledger_ids` |
| `Plugin/Quote/Payment/PlaceOrder` or `sales_order_place_after` observer | Finalize ledger on successful order |
| Observer on order cancel/credit memo | Void/reopen ledger if order refunded before credit consumed |
| `Plugin/Checkout/LayoutProcessor` or Amasty OSC layout slot | Checkout “Apply RM20 Site Credit” toggle (Batch 3C UI) |
| `Block/Customer/Account/SiteCredit.php` + layout | My Account — available credit balance |
| Optional schema patch | `redeemed_order_id` on ledger OR separate `spend` transaction rows |

**No core/vendor/Amasty file edits required** — all via `LivePrawn_CustomerRewards`.

#### 7. Ledger lifecycle: pending → approved → used

| Status | Meaning | When |
|--------|---------|------|
| **pending** | Entitlement recorded, not yet redeemable | Current state after Premium Activation (Batch 2) |
| **approved** | Available to apply at checkout | After activation validation **or** first login / explicit approval step (Batch 3B) |
| **used** | Consumed on a paid order | Order placed with credit applied; set `source_id` on spend row or update earn row + store redemption order increment ID |
| **void** | Admin reversal or cancelled/refunded activation order | Admin tool or refund observer |

**Recommended Batch 3B change:** On premium activation, set credit to **`approved`** immediately (activation order already complete) OR keep **`pending`** until Batch 3B collector ships — then flip to `approved` in same release. Safer for live: **flip to `approved` only when collector is deployed.**

#### 8. Double-use prevention

| Guard | Mechanism |
|-------|-----------|
| One RM20 per activation order | Existing `findBySourceAndRewardType()` on earn row |
| One redemption per ledger entry | Status transition `approved → used` in DB transaction on order place |
| Concurrent checkout | Row lock / `UPDATE … WHERE status='approved'` with affected-rows check |
| Re-submit same quote | Store applied ledger ID on quote extension attribute; recollect idempotently |
| Refund | Observer: if activation order refunded, void earn rows; if redemption order refunded, reopen credit per policy |

Optional schema: unique index on `(customer_id, reward_type, source_type, source_id)` for earn rows (activation order increment ID already unique per Batch 2).

#### 9. Customer display (future)

| Location | Approach |
|----------|----------|
| **My Account** | Block: “Premium Site Credit: RM{X} available” from `BalanceProvider` |
| **Checkout (OSC)** | Toggle/checkbox near payment summary (separate from Prawn Points block) |
| **Order view** | Total line “Premium Site Credit” via `fetch()` on custom collector |

`amrewards/customer/show_balance = 0` today — Prawn Points balance hidden in account; site credit should have **its own** visible block when implemented.

#### 10. Live-site risks

| Risk | Mitigation |
|------|------------|
| Totals collector breaks checkout | Implement on staging first; feature flag in config; deploy collector disabled by default |
| Double discount (credit + points + cart rule) | Define stacking policy; cap total discounts; test on staging |
| Partial credit / tax rounding | Follow Amasty pattern: apply to eligible items subtotal; round RM2 decimals |
| Order refund edge cases | Void/reopen ledger rules documented before go-live |
| Running as root CLI | Permission regression on `generated/` (see Stabilization checkpoint) |
| OpenSearch unrelated | Does not block credit collector; catalog search still broken separately |
| Zero orders on live | Safe to deploy code dormant until staging order test passes |

---

### A. Recommended approach

**Choose Option C: custom ledger-based checkout total** in `LivePrawn_CustomerRewards`.

| Option | Verdict |
|--------|---------|
| **A — 2000 Amasty Prawn Points** | Reject as primary — confusing dual meaning of “points”, dual audit, expiry coupling |
| **B — one-time RM20 cart rule/coupon** | Reject as primary — leaky, no ledger native sync, auto-apply still needs custom code |
| **C — custom ledger totals collector** | **Recommended** — matches business rules (checkout-only, non-transferable, auditable, separate from Prawn Points) |

Option A may remain a **fallback pilot on staging only** if Batch 3B slips schedule — not for live without explicit approval.

---

### B. Step-by-step implementation plan (Option C — Batch 3B/3C)

1. **Config** — add `site_credit/enabled`, `site_credit/allow_with_points`, max stack rules under Live Prawn → Customer Rewards.
2. **BalanceProvider** — query `liveprawn_reward_ledger` for `premium_member_credit` + `status=approved` + `transaction_type=earn`; subtract any `spend` rows.
3. **Activation tweak (Batch 3B)** — change `PremiumActivationProcessor` to set earn row `status=approved` when collector is ready (same release).
4. **Quote total collector** — `SiteCredit` collector applies up to available balance; `fetch()` adds total line.
5. **Quote persistence** — extension attributes for applied amount + ledger entity IDs.
6. **Place-order hook** — on successful order: mark ledger `used`, record redemption order increment ID; rollback on failure.
7. **Cancel/refund observers** — void or reopen per policy.
8. **Customer account block** — show available RM site credit.
9. **Checkout UI (Batch 3C)** — OSC-compatible toggle via layout processor plugin (no core edits).
10. **Admin** — Reward Ledger placeholder shows pending/approved/used counts (extend Batch 2 Premium Members pattern).
11. **Staging tests** — premium activation order → complete → checkout with seafood SKU → RM20 applied once → reorder fails to reuse.

---

### C. Remain pending until staging / order testing

| Item | Blocked until |
|------|----------------|
| Totals collector + place-order integration | Staging clone or approved live test |
| Checkout UI toggle on OSC | Batch 3C after collector verified |
| Flip ledger `pending → approved` on activation | Same release as collector (avoid redeemable credit without collector) |
| Stacking policy with Prawn Points | Business sign-off + staging test |
| Refund/void behavior | Staging order + credit memo test |
| Live order E2E | **Paused** — 0 orders on live today |
| Amasty config changes | Out of scope — do not convert to points on live |

---

## Phase 2 Batch 4A — Referral, Birthday & Anniversary Design (Inspection Only — 2026-06-15)

**Environment:** Live `liveprawn.com` (`/var/www/html/airbenih_stg`). **No implementation.** No checkout changes. No Amasty Affiliate config changes. No coupons. No orders. No emails. No `setup:upgrade`. No cache flush. No core/vendor/Amasty file edits.

### Inspection summary

#### 1. Amasty Affiliate — capabilities & limitations for RM10 Refer-a-Friend

| Item | Finding |
|------|---------|
| Status | **Enabled** — 1 affiliate account, 1 program (**“Pay per Sale”**, program ID 1) |
| Commission model | **Percent-based** — **5%** per sale; **3%** from second order (`from_second_order=1`); **not** fixed RM10 |
| Lifetime | **`is_lifetime=1`** — ongoing commission on referred customer orders, not one-time reward |
| First-order limit | **`restrict_transactions_to_number_orders=0`** — unlimited qualifying orders; **cannot** enforce “one RM10 after friend’s first paid order” without reconfiguration + still wrong payout type |
| Attribution | URL param **`affiliate_code`** (cookie **365 days**); affiliate coupon codes; **separate** from `liveprawn_customer_profile.referral_code` (`LP3E627` format) |
| Payout | Affiliate **withdrawal balance** (min withdrawal **RM50**, min balance **RM100**) — **not** checkout site credit |
| Commission timing | Added on order status **`complete`**; reversed on cancel/closed/fraud per config |
| Self-referral | **`AddValidator`** blocks when affiliate account customer email = order customer email (cookie/coupon path only) |
| Admin void | Affiliate transaction management exists — **commission** model, not Live Prawn ledger void |
| **Verdict** | **Unsuitable** as primary engine for RM10 checkout-only, non-transferable site credit after referred customer’s **first completed paid order**. Keep Amasty Affiliate **unchanged** for its existing commission program; build friend referral in **`LivePrawn_CustomerRewards`**. |

#### 2. `referral_code_fallback` order attribute — safe capture?

| Item | Finding |
|------|---------|
| Attribute ID | **199** — entity type `amasty_checkout`, code `referral_code_fallback`, input **text** |
| Checkout | **Optional**, **visible** below shipping methods (`checkout_step=8`, `is_hidden_from_customer=0`) |
| When captured | **At checkout only** — not at registration |
| Storage | Amasty order attribute EAV on **order** — good audit trail once an order exists |
| Gaps | Does **not** link referrer ↔ referred customer at signup; guest checkout can enter any string; no self-referral / one-reward enforcement by itself |
| **Verdict** | **Safe supplementary fallback** for manual recovery and order-level audit. **Not sufficient** as primary referral capture. Batch 4B must capture code at **registration** (URL/session) and persist in **`liveprawn_referral`**. Keep attribute; optionally hide after registration flow is live. |

#### 3. Customer profile `referral_code` — enough for referral links?

| Item | Finding |
|------|---------|
| Storage | `liveprawn_customer_profile.referral_code` — **unique** index; format **`LP{customer_id}{4-char suffix}`** (e.g. customer 3 → **`LP3E627`**) |
| Created | Registration observer (`ProfileCreator`) — **active** |
| Links | **Sufficient** for shareable URLs, e.g. `https://liveprawn.com/customer/account/create/?ref=LP3E627` or dedicated `/refer/{code}` route in Batch 4B |
| Not needed | Amasty affiliate codes for this program — **separate namespace** |
| **Verdict** | **Yes** — profile code is the canonical referrer identifier for Live Prawn Refer-a-Friend. |

#### 4. Magento customer DOB — enabled / visible now?

| Item | Finding |
|------|---------|
| Core attribute | `dob` exists (attribute ID **11**) on `customer_entity` |
| Store config | **`customer/address/dob_show` not set** → Magento default **`''` (No)** → **`is_visible=0`, `is_required=0`** on storefront |
| Forms | Attribute assigned to admin customer forms; **not** shown on storefront registration/edit until `dob_show` set to **`opt`** or **`req`** |
| Data today | **0 customers** with DOB populated (test customer 3: `dob=NULL`) |
| Profile mirror | `liveprawn_customer_profile.birthday` column exists — **not yet synced** from core DOB |
| **Verdict** | DOB is **optional and hidden** at registration today. Enable **`dob_show=opt`** when business is ready (safe config-only change). Enforce “DOB required before birthday voucher eligibility” in **custom** eligibility checks, not at registration. |

#### 5. DOB storage & admin/account availability

| Location | Available? |
|----------|------------|
| DB | `customer_entity.dob` (date) |
| Admin customer edit | **Yes** — field on adminhtml customer form |
| Storefront account | **Hidden** until `dob_show` configured |
| Live Prawn profile | `liveprawn_customer_profile.birthday` — reserved for cron/eligibility (sync in Batch 4B) |

#### 6. Magento cart price rules — manual birthday/anniversary vouchers?

| Capability | Supported? |
|------------|------------|
| Fixed RM discount (RM10–30) | **Yes** — cart price rule, fixed amount off whole cart |
| Minimum spend | **Yes** — condition on subtotal |
| Customer group tiering | **Yes** — separate rules or conditions per group **5–9** |
| Expiry | **Yes** — `from_date` / `to_date` on rule + coupon |
| One per customer per year | **Partial** — `uses_per_customer=1` per coupon; need **unique coupon per customer** for automation |
| Auto-issue on birthday/anniversary | **No** — requires manual admin export, custom script, or Batch 4B cron + coupon generator |
| Ledger / site-credit wallet sync | **No** — same gap as Batch 3A Option B |
| **Verdict** | **Viable for manual pilot** (admin creates tier coupons each month). **Not** long-term automation without custom module. |

#### 7. Amasty modules — birthday/anniversary automation?

| Module | Birthday | Anniversary |
|--------|----------|-------------|
| **Amasty Rewards `HappyBirthday` cron** | **Daily 00:01** (`happy_birthday_amrewards`); matches `customer_entity.dob` month-day; grants **Prawn Points** via rules with action **`birthday`** | **None** |
| Active rule | Rule ID **3** “Birthday bonus” — **`is_active=0`**, **`amount=30.00` points** (not RM voucher) | — |
| Config | `amrewards/general/days=-1` (offset; awards on configured offset from birthday) | — |
| Tier RM amounts | Would need **separate inactive rules per group** — still **points**, not RM site credit | — |
| Expiry | Points follow program **180-day** expiry — **not** “end of birthday month” or 30-day voucher window | — |
| Min spend on issue | **Not supported** on grant — min spend only at points **redemption** (100 pts min) | — |
| DOB required | Skips customers without DOB (SQL `DATE_FORMAT(dob)` match) | — |
| **Verdict** | **Do not use** for tiered RM birthday vouchers. Keep rule **inactive**. | **No Amasty path** — custom cron only. |

#### 8. Custom ledger-based credit/voucher — long term?

**Yes — same architecture as Batch 3A Option C (recommended).**

| Aspect | Ledger approach |
|--------|-----------------|
| Reward types | `referral_credit`, `birthday_voucher`, `anniversary_voucher` (+ existing `premium_member_credit`) |
| Schema | `liveprawn_reward_ledger` already has `amount`, `status`, `expires_at`, `source_type`, `source_id` |
| Referral link | `liveprawn_referral` table ready — **0 rows** today |
| Redemption | Shared **`SiteCredit` totals collector** (Batch 3B) with per-type min spend + expiry filters |
| Audit / admin void | Unified Reward Ledger + Referrals admin (placeholders exist) |
| vs Amasty Points | Keeps Prawn Points for **loyalty earn/spend**; site credit/vouchers **separate** and checkout-only |

---

### A. Recommendation table

| Feature | Use Amasty/Magento now? | Use manual first? | Custom module needed? | Risk level | Next safe action |
|---------|-------------------------|-------------------|----------------------|------------|------------------|
| **RM10 Refer-a-Friend** | **No** — Amasty Affiliate is commission/withdrawal, not RM10 site credit | **No** — manual RM10 coupons leak and don’t tie to referred customer lifecycle | **Yes** — `LivePrawn_CustomerRewards` referral capture + qualification + ledger | **Medium** (order hooks, fraud rules) | **Design approved** → Batch 4B after Batch 3B collector on staging; keep `referral_code_fallback` as fallback only |
| **Birthday vouchers (tiered RM10–30)** | **No** for automation — Amasty birthday = points only; cart rules = manual | **Optional pilot** — admin-issued tier coupons for known birthdays if marketing needs interim | **Yes** — birthday cron + ledger + eligibility (DOB + group tier) | **Medium** (cron, expiry, tier mapping) | Enable **`dob_show=opt`** when ready (config only); **keep** Amasty birthday rule **inactive**; Batch 4B cron after DOB collection UX |
| **Anniversary vouchers (6/12/24 mo)** | **No** — no native or Amasty automation | **Optional pilot** — manual coupons for known milestones | **Yes** — anniversary cron + ledger (membership anniversary from profile `created_at` or first order date) | **Medium** | Define anniversary anchor date (registration vs first paid order); Batch 4B cron |
| **Site credit redemption (all types)** | **No** — CE has no store credit; Amasty points wrong product | **No** on live | **Yes** — Batch **3B** collector (prerequisite) | **High** on live checkout | **Staging order test first** — same gate as RM20 premium credit |
| **DOB collection** | **Yes** — Magento core `dob` field | n/a | **Sync only** — profile `birthday` mirror + eligibility gate in custom module | **Low** | Set `customer/address/dob_show=opt`; add account dashboard prompt in Batch 4B (no voucher cron until DOB present) |

---

### B. Proposed Phase 2 Batch 4B build plan (do not implement yet)

**Prerequisites:** Batch **3B/3C** site credit collector verified on **staging** (shared redemption path for all credit/voucher types).

#### B1. Referral capture (registration / profile / order)

| Step | Work |
|------|------|
| 1 | **Referral link UX** — My Account shows `referral_code` + copy link (`?ref={code}` or `/refer/{code}`) |
| 2 | **Registration capture** — read `ref` query param / cookie; validate against `liveprawn_customer_profile.referral_code`; store pending row in **`liveprawn_referral`** (`referrer_customer_id`, `referred_customer_id`, `status=pending`) |
| 3 | **Self-referral block** — reject if referrer customer ID = new customer ID or same email/phone heuristics |
| 4 | **One referral per referred customer** — unique index on `referred_customer_id` |
| 5 | **Order fallback** — on first order complete, if no referral row but `referral_code_fallback` order attribute matches valid code, create referral row (late bind); log for admin review |
| 6 | **Profile field** — optional `referred_by_code` on profile or use `liveprawn_referral` only (prefer table) |

#### B2. Referral qualification (first completed paid order)

| Step | Work |
|------|------|
| 1 | **Observer** — extend order-complete pattern from `ProcessPremiumActivationOnOrderComplete` |
| 2 | **Qualify when** — referred customer’s **first** order → state **`complete`**, **grand_total > 0**, valid payment (not free-only) |
| 3 | **Reward** — ledger **`referral_credit`** RM10, `status=approved`, `source_type=referral`, `source_id={referral entity}`; link `liveprawn_referral.reward_ledger_id`; set `status=rewarded` |
| 4 | **Void on cancel/refund** — if first order cancelled/refunded before reward consumed → void ledger + `referral.status=voided` |
| 5 | **Admin void** — Referrals grid action to void suspicious referrals (mirror ledger void) |
| 6 | **Idempotency** — one reward per `liveprawn_referral.entity_id`; skip if referrer = referred |

#### B3. Birthday voucher cron

| Step | Work |
|------|------|
| 1 | **Schedule** — daily cron (e.g. 01:00) — scan customers with DOB / profile `birthday` in **current month** |
| 2 | **Eligibility** — DOB present; active customer; not forbidden; **one issue per calendar year** (ledger or profile flag) |
| 3 | **Amount by group** — Free/Premium **RM10**; VIP Silver **RM15**; Gold **RM20**; Platinum **RM30** |
| 4 | **Expiry** — `expires_at` = min(end of birthday month 23:59, issue_date + 30 days) |
| 5 | **Ledger** — `reward_type=birthday_voucher`, `status=approved`, min spend from config |
| 6 | **DOB sync** — observer on customer save → copy `dob` → `liveprawn_customer_profile.birthday` |
| 7 | **No email** in Batch 4B unless explicitly approved later |

#### B4. Anniversary voucher cron

| Step | Work |
|------|------|
| 1 | **Anchor date** — recommend **`liveprawn_customer_profile.created_at`** (or first **complete paid** order date if business prefers “active customer”) |
| 2 | **Milestones** — 6 mo **RM10**, 12 mo **RM20**, 24 mo **RM30** |
| 3 | **Schedule** — daily cron; match customers hitting milestone **today** (or within grace window) |
| 4 | **Expiry** — `expires_at` = issue + **30 days** |
| 5 | **Eligibility** — active account; milestone not already issued (unique on customer + milestone key) |
| 6 | **Ledger** — `reward_type=anniversary_voucher`, `status=approved` |

#### B5. Ledger entries (shared with Batch 3B)

| Step | Work |
|------|------|
| 1 | Extend **`BalanceProvider`** — sum approved earn rows for all site-credit `reward_type`s minus spends |
| 2 | **Expiry job** — nightly: mark expired `approved` rows as **`expired`** (or exclude in balance query) |
| 3 | **Min spend** — config per reward type; enforce in collector |
| 4 | **Redemption** — single checkout toggle applies available balance (FIFO by expiry recommended) |

#### B6. Admin placeholder screens (extend existing menu)

| Screen | Batch 4B content |
|--------|------------------|
| **Referrals** | Grid: referrer, referred, status, first order, ledger link; void action |
| **Birthday Vouchers** | Issued this month / pending DOB count / config link |
| **Anniversary Vouchers** | Upcoming milestones / issued list |
| **Reward Ledger** | Filter by `reward_type`; status counts |
| **Settings** | Referral amount, birthday tier amounts, min spend, expiry rules, DOB requirement toggle |

#### B7. Testing gate (staging only)

| Test | Pass criteria |
|------|---------------|
| Referral E2E | Register with `?ref=` → friend first paid complete order → referrer RM10 approved → checkout apply once |
| Self-referral | Blocked at registration |
| Refund void | Friend first order refunded → referrer credit voided |
| Birthday | Customer with DOB in month → correct tier amount → expires correctly |
| Anniversary | 6/12/24 mo synthetic dates → single issue each |

**Live deployment:** After staging pass + explicit approval — same constraint as Step 6 (0 orders on live today).

---

### C. Safe to configure now vs wait for staging

| Action | Safe now? | Notes |
|--------|-----------|-------|
| Change Amasty Affiliate program to RM10 / first-order | **No** | Wrong product; user rule: do not change Amasty Affiliate config |
| Enable Amasty birthday rule / cron awards | **No** | Would grant **points**, wrong amounts/expiry |
| Create birthday/anniversary **coupons** | **No** | User rule: do not create coupons on live |
| Set `customer/address/dob_show=opt` | **Yes** (when business ready) | Low risk; exposes optional DOB on registration/account — **no automation** until Batch 4B |
| Marketing copy for referral links using existing `LP*` codes | **Yes** | Codes already generated; **no reward** until Batch 4B |
| Hide `referral_code_fallback` at checkout | **Wait** | Keep visible until registration capture ships |
| Batch 4B code (crons, observers, collector) | **Wait** | After Batch 3B staging order tests |
| Referral/birthday **emails** | **Wait** | Explicit approval + email template review |

---

### D. Recommended implementation approach (summary)

**Referral:** Custom **`LivePrawn_CustomerRewards`** only — registration URL capture → `liveprawn_referral` → qualify on referred customer’s first **complete paid** order → RM10 **`referral_credit`** ledger row → redeem via Batch 3B collector. Amasty Affiliate stays on commission model. `referral_code_fallback` = audit fallback only.

**Birthday / anniversary:** Custom crons → tier/milestone amounts → **`liveprawn_reward_ledger`** with `expires_at` and min spend → redeem via same collector. Optional **manual cart-rule coupons** only as short-term marketing pilot, not architecture. Amasty `HappyBirthday` remains **inactive**.

**Long term:** Unified ledger + site credit collector (Batch 3A Option C) is the **correct** platform for RM10 referral, birthday, anniversary, and premium RM20 credits — one audit trail, checkout-only, non-transferable.

---

## Phase 2 Batch 4B — Referral, Birthday & Anniversary Backend Foundation (Completed 2026-06-15)

**Environment:** Live `liveprawn.com`. **Backend foundation only.** All new automation **disabled by default** via config flags. No checkout collector. No orders. No emails. No `setup:upgrade` (no schema changes). No `setup:di:compile`. No static deploy. Config cache clean only.

### Config flags (Stores → Live Prawn → Customer Rewards)

| Group | Field | Default | Purpose |
|-------|-------|---------|---------|
| Refer-a-Friend | **Referral Enabled** | **No** | Gates `?ref=` cookie/session capture and registration linking |
| Birthday Vouchers | **Birthday Voucher Enabled** | **No** | Gates birthday cron and ledger persistence |
| Anniversary Vouchers | **Anniversary Voucher Enabled** | **No** | Gates anniversary cron and ledger persistence |
| Site Credit | **Site Credit Checkout Redemption Enabled** | **No** | Reserved for Batch 3B totals collector |

Additional: **Referral Cookie Lifetime (days)** default **30**.

### Implemented (Batch 4B)

| Area | Implementation |
|------|----------------|
| **Referral capture** | Frontend `controller_action_predispatch` observer reads `?ref=`; `ReferralCaptureService` validates `LP*` code against profile; stores cookie + customer session **only when Referral Enabled = Yes** |
| **Referral registration** | `ProcessReferralOnRegister` on `customer_register_success` → `ReferralRegistrationProcessor` creates `liveprawn_referral` row (`status=registered`), blocks self-referral and duplicate `referred_customer_id` |
| **Birthday services** | `BirthdayVoucherCalculator` (tier by group 5–9); `BirthdayVoucherGenerator` → ledger `birthday_voucher`, `pending`, expiry = min(+30 days, end of month) |
| **Anniversary services** | `AnniversaryVoucherCalculator` (6/12/24 mo); `AnniversaryVoucherGenerator` → ledger `anniversary_voucher`, `pending`, expiry = +30 days |
| **Crons** | `liveprawn_birthday_vouchers` (02:00), `liveprawn_anniversary_vouchers` (02:15) — **immediate return** when config disabled; log-only stub when enabled (no customer batch yet) |
| **Admin** | Referrals / Birthday / Anniversary pages show enabled flag + row/ledger counts |
| **CLI verify** | `bin/magento liveprawn:rewards:verify-calculations` — dry-run tier math, **no DB writes** |

### Verification (Batch 4B)

| Check | Result |
|-------|--------|
| Config flags default **No** | **Pass** — `referral_enabled=no`, `birthday_enabled=no`, `anniversary_enabled=no`, `checkout_redemption=no` |
| Referral capture while disabled | **Pass** — `captureFromRequestParam('LP3E627')` → `false`, no cookie stored |
| Referral rows created | **0** |
| Birthday/anniversary ledger entries | **0** |
| Dry-run tier calculations | **Pass** — Free/Premium RM10, Silver RM15, Gold RM20, Platinum RM30; 6/12/24 mo RM10/20/30 |
| Module enabled | **Pass** |
| `setup:db:status` | **Clean** (no schema changes) |
| Orders created | **0** |

### Remaining gaps after Batch 4B

| Gap | Batch |
|-----|-------|
| Referral RM10 qualification on first paid complete order | 4C |
| Referral order-attribute fallback binding | 4C |
| Referral admin grid + void action | 4C |
| Birthday cron customer batch + DOB sync observer | 4C |
| Anniversary cron customer batch + milestone anchor date | 4C |
| Enable `dob_show=opt` + account DOB prompt | 4C / UX |
| Flip voucher ledger `pending → approved` policy | 4C + 3B |
| Site credit checkout totals collector (Batch 3B) | **Blocked** — staging order test |
| Customer-facing referral link UI (My Account) | 4C |
| Emails for referral/birthday/anniversary | Deferred — explicit approval |

---

## Hotfix — Birthday/Anniversary admin pages (2026-06-15)

**Issue:** Admin pages `/admin/liveprawn_rewards/birthdayvouchers/index` and `/admin/liveprawn_rewards/anniversaryvouchers/index` failed with:

`Class "LivePrawn\CustomerRewards\Model\ResourceModel\RewardLedger\Collection\Interceptor" does not exist`

**Root cause:** `Collection.php` was correct, but Magento generated interceptor for `CollectionFactory` was missing (developer mode; no `setup:di:compile` on live).

**Fix:** Replaced `CollectionFactory` usage in `BirthdayVouchers/Summary` and `AnniversaryVouchers/Summary` with `RewardLedgerCounter` — direct `ResourceConnection` `COUNT(*)` on `liveprawn_reward_ledger` filtered by `reward_type`. Avoids generated collection interceptors entirely.

**Files changed:**
- `Model/RewardLedgerCounter.php` (new)
- `Block/Adminhtml/BirthdayVouchers/Summary.php`
- `Block/Adminhtml/AnniversaryVouchers/Summary.php`

**Cache:** `cache:clean config block_html` only.

**Verified:** Admin blocks bootstrap without error; ledger counts **0**; feature flags still **disabled**; **0** orders.

### Hotfix follow-up — Premium Members admin page (2026-06-15)

**Issue:** Same `Collection\Interceptor` risk on `/admin/liveprawn_rewards/premiummembers/index` — `PremiumMembers/Summary` used `RewardLedger\CollectionFactory` and `CustomerProfile\CollectionFactory`.

**Fix:**
- Extended `RewardLedgerCounter` with `countByRewardTypeAndStatus()`.
- Added `CustomerProfileCounter` for direct counts on `liveprawn_customer_profile`.
- Updated `PremiumMembers/Summary` to use both counters (no collection factories).

**Verified:** Premium, Birthday, and Anniversary admin summary blocks load; counts match DB (**0** premium profiles, **0** pending credit, **0** birthday/anniversary ledger); **0** orders; feature flags **disabled**.

---

## Phase 2 Checkpoint Audit — 2026-06-15

**Environment:** Live `liveprawn.com` → Magento root `/var/www/html/airbenih_stg`, document root **`/var/www/html/airbenih_stg/pub`**. **Inspect only** — no config/code/orders/cache changes during this audit.

### 1. Customer groups — PASS

| ID | Code | Status |
|----|------|--------|
| 5 | Free Member | Present |
| 6 | Premium Member | Present |
| 7 | VIP Silver | Present |
| 8 | VIP Gold | Present |
| 9 | VIP Platinum | Present |

**Default registration:** `customer/create_account/default_group = **5** (Free Member)`.

### 2. Member pricing — PASS

| Group | Tier price rows | Match General? |
|-------|-----------------|----------------|
| 1 General | 20 | — |
| 4 Distribution | 20 | **Untouched** (20 rows differ from General — pre-existing Distribution pricing preserved) |
| 5 Free Member | 20 | **0 mismatches** vs General |
| 6 Premium Member | 20 | **0 mismatches** vs General |
| 7 VIP Silver | 20 | **0 mismatches** vs General |
| 8 VIP Gold | 20 | **0 mismatches** vs General |
| 9 VIP Platinum | 20 | **0 mismatches** vs General |

### 3. Prawn Points — PASS

| Setting | Value |
|---------|-------|
| Rate | **100 points = RM1** (`amrewards/points/rate = 100`) |
| Active earning rule | **Rule 9** “Prawn Points - 1.5% Member Spend” — **active** |
| Rule 9 groups | **5, 6, 7, 8, 9** only |
| Rule 9 earn rate | **150 points per RM100 spent** (`amount=150`, `spent_amount=100`) |
| Old test rule (ID 8) | **Inactive** |
| Premium SKU exclusion | Rule 9 excludes **`premium-member-activation`** (`grant_points_for_specific_products=1`, exclude list) |
| Expiry | **180 days** |
| Label | **Prawn Points** |

Other Amasty rules (1–7) remain **inactive**. Birthday rule (ID 3) **inactive**.

### 4. Products — PASS

| Entity | SKU | Status | Visibility |
|--------|-----|--------|------------|
| 95 | `premium-member-activation` | **Enabled** | Not Visible Individually |
| 96–98 | CNY deposit SKUs | **Disabled** | Not Visible Individually |
| 99–104 | Family bundle drafts | **Disabled** | Not Visible Individually |

Premium activation: virtual, **RM100**, max cart qty **1** (`max_sale_qty=1`, `use_config_max_sale_qty=0`).

### 5. Checkout/order attributes — PASS

All six Amasty order attributes present (entity type `amasty_checkout`):

| ID | Code |
|----|------|
| 194 | `preferred_delivery_time` |
| 195 | `delivery_note` |
| 196 | `cny_pickup_delivery_date` |
| 197 | `seafood_preparation_note` |
| 198 | `gift_message` |
| 199 | `referral_code_fallback` |

### 6. LivePrawn_CustomerRewards — PASS (automation gated)

| Item | Status |
|------|--------|
| Module enabled | **Yes** (`config.php` + CLI) |
| Tables | `liveprawn_customer_profile`, `liveprawn_reward_ledger`, `liveprawn_referral` — **exist** |
| Test customer profile | Customer **3** → profile entity **1**, referral **`LP3E627`**, membership **`free`** |
| Premium activation automation | **Code live**, config **enabled** — **no live order test** (0 orders) |
| Referral / birthday / anniversary | **Backend present**, config flags **disabled** (referral=no, birthday=no, anniversary=no) |
| Site credit checkout redemption | **Disabled** (`checkout_redemption=no`) |

### 7. Environment — MIXED

| Item | Status |
|------|--------|
| liveprawn.com docroot | **`/var/www/html/airbenih_stg/pub`** (Apache vhost confirmed) |
| True staging URL | **None** — no staging subdomain in Apache config; live and airbenih.com share same Magento instance |
| DB name | `airbenih_stg` (legacy naming on live) |
| Magento mode | **developer** |
| OpenSearch | Configured **`localhost:9200`** — **DOWN** (connection refused); `catalogsearch_fulltext` indexer **Reindex required** (6 in backlog) |
| `setup:db:status` | **All modules up to date** |
| Full `setup:upgrade` | **Still risky** while OpenSearch unreachable (historical blocker for full upgrade path) |

### 8. Data safety — PASS

| Metric | Count |
|--------|-------|
| Orders | **0** |
| Reward ledger rows | **0** |
| Referral rows | **0** |
| Birthday voucher ledger | **0** |
| Anniversary voucher ledger | **0** |
| Customers | **3** (includes test registrants) |

No detectable bulk customer group reassignment beyond configured defaults.

### 9. Risks (current)

| Risk | Severity | Notes |
|------|----------|-------|
| Live order testing paused | **High** | 0 orders — earn/redeem, premium activation, referral qualification untested |
| Checkout site credit collector not built | **High** | Batch 3B deferred; RM20 premium credit ledger-only |
| No true staging | **High** | Production instance used for all dev; DB name `airbenih_stg` is misleading |
| OpenSearch down | **Medium–High** | Catalog search indexer stale; blocks full `setup:upgrade` confidence |
| Premium activation enabled without order test | **Medium** | Observer live; low blast radius until first order |
| Referral/birthday/anniversary flags off | **Low** | Safe dormant state |

### 10. Checkpoint summary

**Completed:** Phase 1 (groups, pricing, Prawn Points, catalog foundations, checkout fields) + Phase 2 Batches 1–2 (module, premium automation), 3A (credit design), 4A (design), 4B (flagged backend).

**Remaining:** Batch 3B/3C checkout collector; Batch 4C referral qualification + voucher crons; staging clone; OpenSearch fix; live/staging order E2E.

**Recommended next 3 steps:**

1. **Execute true staging clone** per [Staging Setup Plan](live-prawn-staging-setup-plan.md) — **required before any order/checkout/reward testing**.
2. **Restore OpenSearch** on staging (or shared host) — fix catalog search indexer; enable safe `setup:upgrade` on staging.
3. **Batch 3B on staging only** — site credit totals collector after staging E2E gate passes (**not on live**).

---

## Batch 3B — Checkout collector gate

**Batch 3B (site credit checkout totals collector) is blocked until a true staging environment exists.**

| Requirement | Status |
|-------------|--------|
| Separate code path (`/var/www/html/liveprawn_stage`) | **Not created** — see [Staging Setup Plan](live-prawn-staging-setup-plan.md) |
| Separate database (`liveprawn_stage`) | **Not created** |
| Separate URL (`stg.liveprawn.com`) | **Not created** |
| Staging verification (§11 in staging plan) | **Pending** |
| Offline-payment E2E on staging | **Pending** |

**Do not implement or enable Batch 3B on live `liveprawn.com` until:**

1. Staging clone executed and separation verified.
2. Premium activation + RM20 redemption tested on staging.
3. Explicit approval to deploy collector to live.

Design reference: [Phase 2 Batch 3A](#phase-2-batch-3a--rm20-site-credit-redemption-design-inspection-only--2026-06-15).

---

## Phase 1 Reward Points Configuration Checklist

Safe admin procedure for replacing the Amasty Rewards **test** earning rule (ID 8). **Completed 2026-06-14** via approved bootstrap script (config writer + rule repository). Order-based verification **paused** pending environment approval.

### Target configuration

| Setting | Target value |
|---------|--------------|
| Program name | **Prawn Points** |
| Earn rate | **1.5% back** on completed paid orders |
| Redemption rate | **100 points = RM1** |
| RM100 spend | Earns **150 points** (= RM1.50 value at 100:1) |
| Issuance trigger | Order status **Complete** only |
| Points expiry | **180 days** initially (business may later choose 90 days) |
| Excluded orders | Cancelled, refunded, failed, pending, unpaid — **no points** |
| Customer group scope | Public rewards club groups only — **exclude** Wholesale, Retailer, Distribution |

**Admin paths (reference):**

- Earning rules: **Marketing → Promotions → Reward Points Earning Rules**
- Global settings: **Stores → Configuration → Amasty Extensions → Rewards Points**

### Current state (after configuration 2026-06-14)

| Item | State |
|------|-------|
| Active earning rule | ID **9**, **`Prawn Points - 1.5% Member Spend`** |
| Earning formula | **150 points per RM100** (`moneyspent`: X=150, Y=100) |
| Redemption rate | **`amrewards/points/rate = 100`** → **100 points = RM1** |
| Expiry | **180 days** (`expiration_behavior = 1`, `expiration_period = 180`) |
| Orders paid with points | Earning **blocked** (`disable_reward = 1`) |
| Customer groups (rule 9) | **5, 6, 7, 8, 9** only — B2B excluded |
| Old test rule | ID **8** **`test`** — **inactive** (not deleted) |
| Balance label | **Prawn Points** |
| Excluded SKUs (rule 9) | **`premium-member-activation`** (Exclude) |

### Admin steps (completed)

**Prerequisite:** Public rewards customer groups created (IDs 5–9). **Done.**

- [x] **1.** Did **not** edit old **test** rule first; created new rule separately.
- [x] **2.** Created earning rule **`Prawn Points - 1.5% Member Spend`** (rule ID **9**).
- [x] **3.** Action: **Get X Points for Each $Y Spent** (`moneyspent`).
- [x] **4.** **Amount (X) = 150** points.
- [x] **5.** **Spent Amount (Y) = RM100**.
- [x] **6.** **Website = Main Website** (website_id 1).
- [x] **7.** **Customer Groups:** Free Member, Premium Member, VIP Silver, VIP Gold, VIP Platinum only (IDs 5–9).
- [x] **8.** Old **test** rule (ID 8) set to **Inactive**; not deleted.
- [x] **9.** Global **Points Spending Rate = 100**.
- [x] **10.** Global **Award Reward Points on Order Status = Complete**.
- [x] **11.** Global **Points Expiration = 180** days.
- [x] **12.** Global **Disable Reward Points for Orders Paid with Reward Points = Yes**.
- [ ] **13.** Test with sample completed orders — **PAUSED** (see [Environment Safety Finding](#environment-safety-finding); do not create orders until approved):

| Order subtotal (eligible) | Expected points (RM100 block rule) |
|---------------------------|-------------------------------------|
| RM99 | **0** |
| RM100 | **150** |
| RM200 | **300** |
| RM250 | **300** (not 375 — see limitation below) |

- [ ] **14.** Document limitation: Amasty Lite uses block spending formula `floor(amount ÷ Y) × X`. With **Y = RM100**, **RM250 earns 300 points, not 375**, unless configured as **1.5 points per RM1** (X=1.5, Y=1) or precise calculation is built in `LivePrawn_CustomerRewards` later.
- [ ] **15.** Record decision:

| Option | Pros | Cons |
|--------|------|------|
| **RM100 block** (X=150, Y=100) | Simpler admin setup; aligns with “150 pts per RM100” messaging | Under-credits amounts not landing on RM100 boundaries (e.g. RM250 → 300 not 375) |
| **RM1 block** (X=1.5, Y=1) | More precise 1.5% on any subtotal | Decimal/rounding behavior — must test on staging |
| **Custom module later** | Exact 1.5% on final paid subtotal | Requires `LivePrawn_CustomerRewards` development |

**Exit criteria:** New rule active; test rule disabled; redemption 100:1; expiry 180 days; B2B groups excluded from earning — **configuration met**. Order verification **pending** staging/live-test approval.

---

## 6. Gaps Remaining

| # | Gap | Severity | Resolution path |
|---|-----|----------|-----------------|
| G1 | Retail customer groups (Free/Premium/VIP) not created | High | Phase 1 Magento config |
| G2 | Member/non-member pricing not set per brief | High | Phase 1 catalog group prices |
| G3 | Prawn Points not at 1.5%; test rule active | High | Phase 1 Amasty Rewards config |
| G4 | Active 80% catalog rule "test" | Critical | Disable immediately in Phase 1 |
| G5 | Site credit (RM20 Premium, RM10 referral) — CE has no native store credit | High | Phase 1: test Amasty Rewards or cart price rule for checkout-only credit; if unsafe → `LivePrawn_CustomerRewards` ledger + checkout credit (Phase 3–4) |
| G6 | Premium activation workflow (group, credit, welcome pack) | High | Product **created** (Batch 1); custom module Phase 3 still required |
| G7 | Unified rewards ledger | High | Custom table Phase 2 |
| G8 | Referral: first paid order trigger, RM10 fixed, no self-referral | High | Test Affiliate Phase 1; custom if fail |
| G9 | Lifetime spend + VIP auto-upgrade | High | Custom module Phase 4 |
| G10 | Birthday/anniversary automated vouchers; DOB optional at signup | Medium | Custom cron Phase 5; manual coupons interim; require DOB save before first birthday voucher only |
| G11 | CNY deposit deduction / slot management | Medium | **Draft products created** (Batch 1, disabled); manual first; custom tracking Phase 5 |
| G12 | Welcome pack eligibility (first order ≥ RM100) | High | Custom module Phase 3 |
| G13 | Platinum RM100 seafood reward cap | Medium | Custom ledger + admin approval |
| G14 | Review rewards automation | Low | Defer; manual Phase 1 |
| G15 | Pre-order / delivery / order attributes unconfigured | Medium | Phase 1 Amasty config |
| G16 | Double Points Day scheduling | Low | Confirm Amasty; custom campaign hook if needed |
| G17 | B2B groups (Wholesale/Retailer/Distribution) coexist | Info | Keep separate; public site uses retail groups only |

---

## 7. Safest Phase-by-Phase Build Order

Aligned with product brief functional priorities. **No code, config, cache, or deploy changes during this planning document update.**

### Phase 1 — Configure existing Magento/Amasty (config + catalog only)

**Goal:** Maximize native capabilities; confirm gaps before custom code.

1. **Safety cleanup:** Disable catalog rule "test" (80% off). Document/remove test reward rule ID 8.
2. **Customer groups:** Create/confirm Free Member, Premium Member, VIP Silver, VIP Gold, VIP Platinum. Inspect whether **Default Group** config can assign new registrants to Free Member (`Stores → Configuration → Customers → Customer Configuration → Create New Account Options → Default Group`). Document finding; defer to custom module if not safe.
3. **Pricing:** Configure group prices per brief (member vs non-member) on prawn SKUs.
4. **Amasty Reward Points Lite:** Configure 1.5% earning, 100:1 redemption, complete-only issuance, 90/180-day expiry, disable earn on points-only orders. Confirm subtotal/shipping treatment on staging.
5. **Amasty Delivery Date:** Enable and configure lead times, blackout dates, CNY window.
6. **Amasty Order Attributes:** Create checkout fields (delivery note, time, CNY date, prep note, gift message, referral code fallback).
7. **Amasty Special Promotions Lite:** Basic member-only and first-order coupon rules.
8. **Amasty Affiliate pilot:** Test referral link/code → friend registration → RM10 after first paid order. **Decision gate:** proceed with Affiliate or flag for custom.
9. **Catalog products:** Premium Member Activation (virtual RM100); CNY Price Lock deposits (RM30/50/100); family bundle products.
10. **Amasty Pre Order Lite:** Enable preorder labels for CNY SKUs; document deposit redemption manual process if deduction unsupported.
11. **Customer account / DOB:** Confirm DOB attribute availability; keep DOB **optional at registration**; plan account prompt so DOB is required only before birthday voucher eligibility.
12. **RM20 Site Credit pilot:** On staging, test Amasty Rewards (2000 pts) or single-use RM20 cart rule for Premium welcome credit — confirm checkout-only, non-transferable behavior; otherwise record as custom-module gap (G5).
13. **CMS copy:** "Buy fresh. Earn rewards. Save more every time." + "Join as a member and save up to RM15/kg."

**Exit criteria:** Member pricing live; 1.5% points earning verified on test order; checkout fields work; referral pilot tested; gap list G5–G12 confirmed.

### Phase 2 — Custom module foundation (`LivePrawn_CustomerRewards`)

**Goal:** Scaffold only; no frontend redemption yet.

1. Create module at `app/code/LivePrawn/CustomerRewards/`.
2. `setup:upgrade` on staging: custom tables (`liveprawn_customer_profile`, `liveprawn_reward_ledger`, `liveprawn_referral`).
3. Admin menu **Live Prawn Rewards** (placeholder grids).
4. On customer registration: create profile, generate referral code.
5. Reward ledger model + repositories.
6. Verify customer groups exist (no duplicate creation logic).
7. **No frontend redemption yet.**

**Exit criteria:** Module installs; admin menu visible; profile + referral code on new registration; ledger accepts manual test entries.

**Status:** Phase 2 Batch 1 **completed 2026-06-15** — see [Phase 2 Batch 1](#phase-2-batch-1--custom-module-foundation-completed-2026-06-15). Premium activation automation **completed Batch 2** — see [Phase 2 Batch 2](#phase-2-batch-2--premium-activation-automation-completed-2026-06-15). RM20 checkout redemption, welcome pack fulfillment, VIP automation, birthday/anniversary cron **not implemented**.

### Phase 3 — Premium Member activation

1. Observer/plugin: detect completed order containing Premium Member Activation SKU.
2. Assign Premium Member customer group.
3. Update customer profile (`premium_activated_at`, `membership_type`).
4. Issue RM20 site credit → ledger (pending/approved). Use Amasty Rewards or cart rule if Phase 1 pilot passed; otherwise implement checkout credit in this module.
5. Set `welcome_pack_status = eligible`.
6. Validate welcome pack on first subsequent paid order (min RM100) — flag only; fulfillment may remain manual.

**Exit criteria:** End-to-end premium purchase → group change → RM20 credit in ledger → welcome pack eligible.

### Phase 4 — Points, referral, VIP

1. Confirm/sync 1.5% Prawn Points with Amasty (plugin if tier multipliers needed later).
2. Referral: RM10 credit after referred customer's first paid completed order (if Affiliate failed Phase 1 gate).
3. Lifetime spend calculation (completed paid orders only).
4. Auto-upgrade VIP Silver (RM1k) / Gold (RM3k) / Platinum (RM5k).
5. Platinum: one-time premium seafood reward ≤ RM100 → ledger.
6. Block self-referral; void on refunded first orders.

**Exit criteria:** Referral RM10 works; VIP upgrades on qualifying orders; ledger audit trail complete.

### Phase 5 — Birthday, anniversary, CNY

1. Cron: birthday vouchers by tier (RM10–30) for customers **with DOB on file only**; expire end of month or 30 days. Account prompt to add DOB before eligibility (DOB remains optional at registration).
2. Cron: anniversary vouchers at 6/12/24 months.
3. CNY Price Lock: deposit tracking, slot limits, ledger entries.
4. Integrate delivery date for CNY collection/delivery scheduling.
5. Double Points Day campaigns (Amasty rules or custom campaign flag).

**Exit criteria:** Automated voucher issuance tested; CNY deposits tracked; expiry/void rules enforced.

### Phase 6 — Hardening, review rewards, group buy (optional)

1. Review rewards (RM5/RM10) if automation ready; else remain manual.
2. Group buy rules (5kg/10kg/20kg) via Special Promotions or custom.
3. Admin void/adjust workflows + Amasty Admin Actions Log audit.
4. QA: checkout with points + site credit + vouchers stacking rules.
5. Production deploy: `setup:upgrade`, compile, static content, cache flush (production window only).

**Exit criteria:** All business rules §2.20 enforced; no test rules active; admin can inspect/void all reward types.

---

## 8. Amasty Module Usage Plan (from brief + inspection)

### Amasty Reward Points Lite

**Use for:** 1.5% Prawn Points; checkout redemption; points expiry.

**Confirm on staging:**

- [ ] Can represent 1.5% value correctly?
- [ ] Points earned only after completed order?
- [ ] Refunded/cancelled orders excluded?
- [ ] Redemption cap configurable?
- [ ] Expiry 90/180 days configurable?

### Amasty Affiliate

**Use for:** Referral code/link; referred customer tracking; referrer reward.

**Confirm on staging:**

- [ ] Fixed RM10 credit (not commission)?
- [ ] Release only after friend's first paid order?
- [ ] Self-referral prevention?
- [ ] Customer referral model (not affiliate marketer)?

### Amasty Special Promotions Lite

**Use for:** First-order voucher; member-only promos; family bundle campaigns; CNY campaign; group buy; Double Points substitute if points module cannot do 2×.

### Amasty Pre Order Lite

**Use for:** CNY preorder visibility; festive order planning.

**Confirm:** Deposit support; partial payment; final payment deduction.

### Amasty Delivery Date

**Use for:** Delivery date selection; CNY delivery planning; order scheduling.

### Amasty Order Attributes

**Use for:** Delivery note; preferred time; CNY pickup/delivery date; preparation note; gift message; optional referral code.

### Amasty One Step Checkout Pro

**Use for:** Faster checkout; improved conversion (already configured).

### Amasty Admin Actions Log

**Use for:** Audit trail; reward adjustment tracking; admin change history.

---

## 9. Phase 1 Planning Checklist

| Task | Status |
|------|--------|
| Requirements documented from product brief | Done |
| Scope exclusions documented | Done |
| Inspection findings preserved | Done |
| Environment safety finding documented | Done (2026-06-14) |
| Feature-to-module mapping complete | Done |
| Config vs manual vs custom split documented | Done |
| Gaps identified | Done |
| Phase build order documented | Done |
| Customer groups created (IDs 5–9) | Done |
| Default Free Member registration | Done |
| Member tier prices copied to reward groups | Done |
| Prawn Points configuration (rule 9, global settings) | Done |
| Batch 1 catalog (Premium + CNY drafts) | Done (2026-06-14) |
| Order-based Prawn Points testing | **Paused** — staging clone or live-test approval required |
| No Magento core modified | Confirmed |
| No custom module created | Confirmed |

---

## Restaurant Manual Onboarding + Introducer Assignment + Commission Tracking (2026-06-15)

**Environment:** Live `liveprawn.com`. **Manual B2B foundation only.** No storefront exposure. No automatic payout. No checkout changes. No retail rewards automation changes.

### PART A — Inspection verdict

| Area | Finding | Extend? |
|------|---------|---------|
| `liveprawn_customer_profile` | Retail membership / VIP / referral code | **No** — retail-focused |
| `liveprawn_referral` | Refer-a-Friend (`referrer_customer_id` → `referred_customer_id`) | **No** — different lifecycle |
| `liveprawn_reward_ledger` | Site credit / voucher ledger | **No** — not introducer commission |
| `customer_entity` + groups | Restaurant group **ID 10**, Distribution **ID 4** | Reference only |
| `admin_user` | Magento admin users for internal introducers | Reference only |
| **Amasty Affiliate** | Commission/withdrawal for affiliates | **Ignore** for Restaurant assignment — separate B2B introducer model in `LivePrawn_CustomerRewards` |

**Preferred:** **Option 2 — new table `liveprawn_restaurant_assignment`** (+ `liveprawn_restaurant_commission` ledger). Implemented.

### PART B/E — Schema

| Table | Purpose |
|-------|---------|
| `liveprawn_restaurant_assignment` | Manual restaurant ↔ introducer mapping, commission basis, status, date range, notes |
| `liveprawn_restaurant_commission` | Pending/approved/paid/void commission rows per completed order (unique `order_id`) |

Applied via declarative schema (`setup:db-schema:upgrade` on live — schema-only, no data migration).

### PART C — Admin (manual onboarding)

**Menu:** Live Prawn Rewards → **Restaurant Assignments** / **Restaurant Commissions**

| Screen | v1 content |
|--------|----------------|
| Restaurant Assignments | Summary counts, **manual assignment form** (POST save), recent assignments table |
| Restaurant Commissions | Summary counts, recent pending commission rows (read-only v1) |

**Not on storefront.** Admin manually creates Restaurant customer account and sets customer group = Restaurant (ID 10) in Magento Customers — this module records introducer + commission basis only.

### PART D/F — Commission calculation (report-only, flag-gated)

**Default config (no auto-payout):**

| Setting | Default |
|---------|---------|
| Restaurant Commission Tracking Enabled | **No** |
| Restaurant Customer Group ID | **10** |
| Distribution Customer Group ID | **4** |
| Default Commission Type | **percentage** |
| Default Commission Value | **3** (% of order subtotal) |

**When enabled**, observer on `sales_order_save_after` → `RestaurantCommissionProcessor`:

1. Order transitions to **Complete** (not canceled/closed; not already complete)
2. Customer group = Restaurant (10)
3. Active `liveprawn_restaurant_assignment` exists
4. Commission type ≠ `none`
5. Creates **`pending`** row in `liveprawn_restaurant_commission` (idempotent by `order_id`)
6. Admin reviews → approve/paid manually in a later batch (no bank payout, no customer credit, no email)

**Commission models supported in calculator:**

| Type | Calculation |
|------|-------------|
| `percentage` | `order_subtotal × (value / 100)` |
| `fixed_per_order` | Fixed RM per completed order |
| `service_share` | Reserved (0 until service-fee orders ship) |
| `none` | Skip |

Per-assignment commission type/value overrides config defaults on save.

### PART G — Feature flag

`Stores → Live Prawn → Customer Rewards → Restaurant Commission Tracking → Restaurant Commission Tracking Enabled` = **No** (default).

When **No**: no commission rows generated; admin can still create assignment records.

### Validation rules (assignment save)

| Rule | Enforcement |
|------|---------------|
| `restaurant_customer_id` in Restaurant group (10) | `AssignmentValidator` |
| `introducer_type = distributor_customer` → introducer in Distribution group (4) | `AssignmentValidator` |
| `introducer_type = admin_user` → valid `admin_user.user_id` | `AssignmentValidator` |
| Introducer name snapshot | Auto-resolved from customer/admin name when possible; required for `manual` |

### Files (LivePrawn_CustomerRewards)

| Area | Paths |
|------|-------|
| Schema | `etc/db_schema.xml` |
| Config | `etc/config.xml`, `etc/adminhtml/system.xml`, `Model/Config.php` |
| Models | `Model/RestaurantAssignment.php`, `Model/RestaurantCommission.php`, `Model/Restaurant/*` |
| Observer | `Observer/ProcessRestaurantCommissionOnOrderComplete.php` |
| Admin | `Controller/Adminhtml/Restaurantassignments/*`, `Controller/Adminhtml/Restaurantcommissions/*`, blocks + templates |

### Remaining (future batches)

| Item | Notes |
|------|-------|
| Full admin UI grid + edit/delete | v1 uses form + recent table |
| Approve / paid / void actions on commission rows | Manual SQL or next batch |
| Service plan share from Restaurant Credit Terms products | When service products go live |
| Storefront restaurant onboarding | Explicitly out of scope — admin manual only |

---

## Checkpoint Audit — Restaurant Assignment + Commission Foundation (2026-06-15)

**Type:** Inspect only on live `liveprawn.com`. No orders, invoices, group/price changes, flag enablement, checkout, or retail rewards changes.

### 1. Database tables

| Table | Status | Rows | Structure |
|-------|--------|------|-----------|
| `liveprawn_restaurant_assignment` | **EXISTS** | **0** | 16 columns: restaurant customer, company, introducer type/IDs, name snapshot, commission type/value, status, dates, notes, audit timestamps. FK → `customer_entity.entity_id` |
| `liveprawn_restaurant_commission` | **EXISTS** | **0** | 19 columns: assignment link, order id/increment/subtotal, commission calc fields, status lifecycle, audit fields. **UNIQUE** on `order_id`. FKs → assignment + `customer_entity` |

**Pass** — schema matches design; no orphan data.

### 2. Feature flag

| Setting | Value | Pass |
|---------|-------|------|
| Restaurant Commission Tracking Enabled | **No** | ✅ |
| Restaurant group ID (config) | **10** | ✅ |
| Distribution group ID (config) | **4** | ✅ |
| Default commission type | **percentage** | ✅ |
| Default commission value | **3** | ✅ |

Commission tracking was **not** enabled during this audit.

### 3. Admin pages

| Page | Route | HTTP | Block DI |
|------|-------|------|----------|
| Live Prawn Rewards → Restaurant Assignments | `liveprawn_rewards/restaurantassignments/index` | **200** (URL reachable) | **OK** |
| Live Prawn Rewards → Restaurant Commissions | `liveprawn_rewards/restaurantcommissions/index` | **200** (URL reachable) | **OK** |

Menu, ACL, layout XML, and controllers present. No storefront routes for restaurant assignment/commission.

### 4. Manual assignment form (load-only)

Template `restaurant_assignments.phtml` confirms fields render without save:

| Field | Present |
|-------|---------|
| Restaurant customer ID | ✅ |
| Restaurant company name | ✅ |
| Introducer type (4 options) | ✅ |
| Introducer customer ID | ✅ |
| Introducer admin user ID | ✅ |
| Introducer name snapshot | ✅ |
| Commission type (4 options) | ✅ |
| Commission value | ✅ |
| Status (3 options) | ✅ |
| Notes | ✅ |

Also: start/end date fields (optional scheduling). **No save performed** in audit.

### 5. Existing data counts

| Metric | Count |
|--------|------:|
| Assignment rows | **0** |
| Commission rows | **0** |
| Orders | **7** |
| Customers | **5** |
| Customer groups 0–10 | **11** (includes Restaurant ID 10) |
| Retail `liveprawn_reward_ledger` | **2** (unchanged retail ledger) |
| Retail `liveprawn_referral` | **0** |
| `liveprawn_customer_profile` | **3** |

### 6. Safety

| Check | Result |
|-------|--------|
| Commission rows while flag off | **0** — none generated |
| Checkout changes | **None** — no LivePrawn checkout/frontend restaurant code |
| Retail rewards automation | **Unchanged** — `ProcessPremiumActivationOnOrderComplete` still sole retail order-side automation; referral/birthday/anniversary flags still off |
| Prawn prices | **Unchanged** — e.g. product 75 base RM48, product 85 base RM51 |
| Restaurant tier prices | **20 rows** on prawn SKUs 75–94 for group 10 |
| Existing customers changed | **No evidence** — customer count stable at 5 |
| Customer groups changed | **No** — groups 0–10 intact |

### 7. Observer safety

`RestaurantCommissionProcessor::process()` **returns immediately** when `Config::isRestaurantCommissionTrackingEnabled()` is false (first line of processor).

**Runtime test:** Simulated complete-order transition on latest real order with flag off → commission count **0 → 0** (delta 0).

Observer registered separately from premium activation; does not modify retail reward logic when flag is off.

### 8. Restaurant group

| Item | Value |
|------|-------|
| Group ID | **10** |
| Group code | **Restaurant** |
| Tax class | **3** (Retail Customer) |
| Prawn tier prices (75–94) | **20** Restaurant-tier rows |

### 9. Checkpoint verdict

| Area | Status |
|------|--------|
| Schema | **Ready** |
| Feature flag default | **Safe (Off)** |
| Admin foundation | **Ready** |
| Commission automation | **Dormant** until flag enabled + assignments exist |
| Retail / checkout isolation | **Pass** |

**Errors found:** None.

**Recommended before enabling commission tracking:** Create at least one validated assignment in admin; confirm approve/paid workflow in a future batch; test on staging or a controlled complete order with explicit approval.

---

*End of planning document.*
