Files
orion/docs/proposals/merchant-intake-checklist.md
Samir Boulahtit 29b2170448
All checks were successful
CI / ruff (push) Successful in 17s
CI / pytest (push) Successful in 2h39m52s
CI / validate (push) Successful in 31s
CI / dependency-scanning (push) Successful in 35s
CI / docs (push) Successful in 52s
CI / deploy (push) Successful in 1m43s
docs(onboarding): merchant intake checklist (EN + FR)
Practical field-by-field intake doc for the first merchants — maps
each question to its DB column so the call → admin UI is 1:1.
Includes a section on marketing-material reuse aimed at franchisees,
with written-authorization clauses for the future marketing module.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 23:08:35 +02:00

15 KiB
Raw Blame History

Merchant Intake Checklist — First Store Onboarding

A practical list of every datum to collect from a new merchant before flipping their first store live on the loyalty platform. Each field is mapped to the actual database column behind it, so what you collect in the intake meeting maps 1:1 to the admin UI you'll fill in afterwards.

Use this as a sharable form, or as a script for the first onboarding call.

How to use this doc

  1. Send the merchant the "What you need to send us" sections (17) ahead of the kickoff call, so they have logos / VAT numbers / staff info ready.
  2. Use the business decisions sections (3, 5) to drive the actual conversation — these are the choices only they can make.
  3. After the call, populate the admin UI in the order below; the model enforces this dependency chain (merchant → store → loyalty program → staff).

TL;DR — what you absolutely cannot launch without

  • Legal business name + VAT number + business address
  • Owner email (login + invitation target)
  • Store name + store code (URL slug)
  • Loyalty program type (stamps / points / hybrid) + reward structure
  • Privacy policy URL (GDPR)
  • Brand logo (square PNG, transparent bg)
  • Brand primary color (hex)
  • At least one staff PIN

Everything else can be filled in iteratively post-launch.


1. Business identity (the merchant entity)

One per merchant — feeds the merchants table.

Field Required? DB column Notes
Legal business name name Appears on invoices + email footers
Trading name (if different) optional (use name) The name customers see
Business description recommended description One-line tagline
VAT / tax number EU tax_number LU format: LU12345678
Business registration number tax_number (or separate field if available) LU: RCS Lxxxxxx
Business address business_address Street + city + ZIP + country
Primary contact email contact_email Where invoices + platform alerts go
Primary contact phone recommended contact_phone For support callbacks
Website URL optional website Linked from storefront footer

2. Owner / admin account

The human who logs in as merchant owner.

Field Required? Notes
Full name Shown on audit logs
Email (login) Invitation goes here — must be deliverable
Phone recommended
Preferred UI language (en / fr / de / lb) Drives the admin dashboard's language

3. Each store / point of sale

Repeat per location. Feeds the stores table. The platform supports multi-location from day one — even single-store merchants live in this shape.

Field Required? DB column Notes
Store name name E.g. "Fashion Hub City Concorde"
Internal store code store_code UPPERCASE slug, no spaces — used in URLs (/store/FASHIONHUB). Pick once, hard to change
Subdomain optional subdomain E.g. fashionhub.rewardflow.lu for the storefront
Physical address business_address Per-location, overrides merchant address if different
Local contact email optional contact_email Overrides merchant-level if store has its own
Local phone optional contact_phone
Default tax rate % optional letzshop_default_tax_rate Defaults to 17% (LU standard VAT)
Default UI language default_language / dashboard_language What the staff terminal opens in
Customer-facing languages storefront_languages Subset of {en, fr, de, lb} for LU
Opening hours optional not in schema yet Useful context for support

4. Staff (per store, for each cashier)

Feeds users + store_users (invitation flow).

Field Required? Notes
Full name Shown on the tablet PIN screen
Email if web access needed Owner-only PIN-on-tablet operators don't need an account
4-digit PIN They pick it; you set it on /admin/loyalty/pins; staff types it on the tablet for every transaction
Employee ID / staff number optional Shown alongside name in audit trail
Role One of: merchant_owner, store_admin, store_staff

5. Loyalty program — the business decisions

One program per merchant. Feeds the loyalty_programs table. This is where most of the kickoff conversation happens — help them choose.

5.1 Program type

Type When to recommend
Stamps "Buy 10, get 1 free" model. Cafés, hairdressers, lunch spots, anywhere with a clear unit of sale
Points "Earn X points per €, redeem on rewards menu". Retail with varied basket sizes
Hybrid Both at once. Rare for v1 — defer

5.2 If stamps

Field Typical value Notes
stamps_target 10 Stamps to fill a card
stamps_reward_description "Free coffee" Customer-facing reward name
stamps_reward_value_cents 500 (= €5) Internal value for analytics

5.3 If points

Field Typical value Notes
points_per_euro 1, 5, or 10 The earn rate
welcome_bonus_points 50100 Awarded on enrollment, makes new customers feel rewarded
minimum_purchase_cents 500 (= €5) Minimum sale to earn anything — kills chewing-gum farming
minimum_redemption_points 100 Minimum points to redeem anything
points_expiration_days 365 After this, unredeemed points lapse
points_rewards (JSON list) see below The reward menu

Each entry in points_rewards needs: name, points_required, description, value. Example:

[
  {"name": "€5 voucher", "points_required": 100, "description": "Apply at checkout", "value": 500},
  {"name": "€15 voucher", "points_required": 250, "description": "Apply at checkout", "value": 1500},
  {"name": "Free product XYZ", "points_required": 400, "description": "Pickup in store", "value": null}
]

5.4 Anti-fraud knobs

Field Default When to change
cooldown_minutes 0 Set 3060 for high-volume cafés to stop staff abuse
max_daily_stamps 10 Lower if low-volume; this caps a single card's daily stamps
require_staff_pin true Recommended true for >1 staff member; tablet handles offline

5.5 Cross-location behaviour

This is on the merchant settings (merchant_loyalty_settings), not the program:

Setting Default Notes
allow_cross_location_redemption on Earn at Store A, redeem at Store B? Yes for chains, no for indies sharing infrastructure
allow_void_transactions on Some merchants disable for fraud control
require_order_reference off Useful if integrating with their POS/till — links each loyalty transaction to a sale receipt

6. Branding assets

Collect as files, not links — we host them.

Asset Format Size DB field
Primary logo PNG, transparent bg 600×600 min, square logo_url
Hero banner JPG / PNG 1200×400 hero_image_url
Brand primary color Hex e.g. #7C3AED card_color
Brand secondary color Hex e.g. #10B981 card_secondary_color
Card display name Short string e.g. "Fashion Hub Rewards" card_name

The logo doubles as the Google Wallet pass logo, so 600×600 minimum with transparent background is the practical floor — Google enforces clarity.

7. Compliance & GDPR

Required for go-live, especially in Luxembourg.

Field Required? DB field Notes
Privacy policy URL EU privacy_url Linked from enrollment form. Their site or your CMS
Loyalty T&C terms_text or terms_cms_page_slug Inline text or CMS page slug. Cover: how points work, expiry, when rewards can be revoked, contact for issues
DPO contact (if applicable) depends on size not in schema LU rule: >5k customer records → designated DPO
Marketing consent implicit (enrollment form has the checkbox) Required if you'll send birthday / re-engagement emails

8. Tablets (if you provide the POS hardware)

Question Why
How many tablets per store? Determines how many device pairings to set up
Existing Android tablets? Model + OS? Need Android 8.0+ (API 26), Play Services. Fire OS won't work
Source tablets for them? Lenovo Tab M11 or Samsung Galaxy Tab A9 (€100200 each) — known good
Mounting? Counter stand or wall? Affects power/charging plan
Wifi at each location Offline queue handles brief outages, not all-day. Confirm wifi at the counter

9. Initial data migration (nice-to-have)

Question Why
Existing loyalty customer list? If they're switching from another system or paper cards, bulk-import via CSV (email, name, balance, enrollment date)
Approximate initial customer count? Sizes capacity discussion
Current monthly transaction volume Same

10. Marketing material reuse (for the future marketing module)

Many of our early merchants are franchisees (e.g. fashion, food, beauty chains) and receive a steady stream of campaign material from their franchisor — banners, email templates, social posts, seasonal promotions. The future marketing module aims to republish this material at the local-store level: a franchisee shouldn't have to design their own birthday email when corporate already produces five a year.

At intake, ask permission-style questions so we have a green light before we build the ingestion pipeline. We are not asking them to do anything today — we're inventorying sources and getting written authorization.

10.1 Existing marketing material — what to inventory

Question Why we ask
Is the merchant a franchisee? Of which brand? Determines which corporate sources may exist
Do they receive a regular email newsletter from the franchisor? Forward us 35 recent ones Lets us assess content type, frequency, language mix, formatting
Is there a franchisor extranet / portal where campaigns are published? URL + their login (read-only) The ideal source: structured, dated, multilingual
Social handles the franchisor posts under (Instagram, Facebook, LinkedIn) Public, scrapeable, but low signal-to-noise
WhatsApp / Telegram broadcast groups they're part of Sometimes the only channel — manual forwarding may be the only path
PDF / image packs received by email or download link Common for seasonal campaigns; ask them to share the latest
Frequency: weekly / monthly / per-campaign Sizes ingestion volume
Languages the franchisor publishes in Influences whether we re-use or re-translate

10.2 Reuse authorization — get this in writing

Before any scraping or republishing happens, the merchant must authorize us. Capture in the intake (a checkbox on the onboarding form or a clause in the merchant agreement):

  • "I authorize {platform} to ingest marketing material I forward, share, or grant access to, and to republish it on my behalf via the loyalty/marketing channels offered by the platform."
  • "I confirm I have the right (as franchisee) to use this material in local marketing, and that the franchisor's brand guidelines or licensing terms allow republication via third-party platforms."
  • Forward us the franchisor's brand guidelines / co-op marketing policy if one exists. This determines what we can and can't do safely.

10.3 Practical capture paths (least-effort first)

For the future marketing module, in order of how easy they are to implement:

  1. Forward-to-inbox. Give the merchant a per-store email alias like marketing+FASHIONHUB@rewardflow.lu. They forward any franchisor email there. We parse + categorize.
  2. Drag-and-drop upload. A page where the merchant pastes a URL or uploads a PDF/image; we OCR/parse + queue for review.
  3. Authenticated extranet pull. They give us read-only credentials to the franchisor portal; we poll. Highest signal, highest legal bar — needs explicit franchisor clearance.
  4. Public social scrape. Last resort, only for material the franchisor publishes openly. Respect robots.txt and platform ToS.

10.4 Republish channels we can plug into

What we do with this material once captured:

  • Storefront banner rotation (already exists in CMS)
  • Loyalty welcome / re-engagement / birthday emails (loyalty module v1 — fixed templates; marketing module v2 — campaign-driven)
  • SMS / WhatsApp (marketing module v2, deferred)
  • Push notifications via the Wallet pass (Google Wallet supports this — class-level updates push to every customer's phone)

10.5 Red flags to surface back to the merchant

If during intake any of these come up, flag for legal review before we touch the material:

  • Material contains the franchisor's trademarks in a way the franchisee doesn't have explicit license to use
  • Material references third-party brands (co-promotions with other brands) — those brands didn't consent to our platform
  • Material is in a language the merchant's customer base doesn't speak — we don't auto-translate without permission
  • Personal data of named individuals (testimonials, photos) — GDPR consent chain may not extend to us

11. Test customer for verification

Before sending the merchant to real customers, run the 8 user-journey tests with two test accounts:

  • The merchant owner's personal email
  • A team member or your own email

The end-to-end test list lives in app/modules/loyalty/docs/user-journeys.md.


Suggested fill-in order in the admin UI

The model has hard FK dependencies, so do it in this order:

  1. Create the merchant (/admin/merchants/new) — needs § 1.
  2. Invite the owner — needs § 2.
  3. Create the store(s) (/admin/stores/new) — needs § 3.
  4. Create the loyalty program (/admin/loyalty/programs/new) — needs § 5 + § 6 + § 7.
  5. Create staff PINs (/admin/loyalty/pins/new per store) — needs § 4.
  6. Configure cross-location settings (/admin/loyalty/settings/{merchant}) — needs § 5.5.
  7. (Optional) bulk-import customers via CSV — needs § 9.
  8. Pair tablet(s) at each store (/admin/loyalty/terminals/new, QR or manual) — needs § 8.

Reference