Part 2 of 7 · Loyalty tracker series ~4 min read

How a shopper joins the loyalty program

The tracker only earns points for people it knows about. So the first job is making it easy to become a member — easy enough that nobody loses points just because signing up was a hassle. There are three ways a shopper joins: they fill in a short form, a staff member adds them at the counter, or a sale comes in for a phone number the system has never seen and it creates the member on the spot. The first two are obvious. The third exists because in real life a customer says “yeah, add my number” while three other people are waiting.

Key takeaways

  • Three sign-up lanes feed one member store: a web form, a staff quick-add, and auto-enroll on first sale.
  • The member store is DynamoDB, keyed by phone number, because balances must be exact and fast.
  • Auto-enroll never loses points — an unknown phone on a sale creates a member before points are added.
  • Email is optional and confirmed once, so the shop only ever mails people who asked for it.
  • The same member record is used by every later step: earn, redeem, and the lapsing nudge.

Three lanes into one member store

Three sign-up lanes funnel into one member store A diagram with three vertical lane columns at the top and a single unified row at the bottom. Lane one, Sign-up form: a shopper fills in a short web form with name, phone, and an optional email; the form posts to a Lambda Function URL that writes the member to DynamoDB and, if an email was given, sends a one-tap confirm so only people who asked get mailed. Lane two, Staff quick-add: at the counter staff open a small page, type the customer's phone and name in a few taps, and the same Function URL writes the member; email can be added later. Lane three, Auto-enroll on sale: a sale arrives for a phone number the system hasn't seen; the earn function creates a member right then so the points aren't lost, marks the record as needs-email, and the next balance email invites the customer to add their address. All three lanes converge on the same DynamoDB member store, keyed by phone number, holding name, email, opt-in flag, balance, and last-seen date. A note at the bottom: the member store is the source of truth — every later step reads and writes the same record. Lane 1 · web form Sign-up form • Shopper enters name, phone, email • Function URL writes member to DynamoDB • Email gets a one-tap confirm • Member is live right away Lane 2 · at the counter Staff quick-add • Staff open the quick-add page • Type phone and name • Same Function URL writes the member • Email added later if they like Lane 3 · on first sale Auto-enroll • Sale arrives for an unknown phone • Earn function creates a member on the spot • Marked needs-email; points still earned • Next email invites them to add it DynamoDB member store (source of truth) phone · name · email · opt-in · balance · tier · last-seen · joined keyed by phone number — every later step reads and writes this record to earn engine, per sale The member store is the source of truth — every later step reads and writes the same record.
Fig 2. Three lanes converge on one member store. The store is the source of truth; the form, the quick-add, and auto-enroll all write into the same DynamoDB record keyed by phone number, so the earn engine, the redeem desk, and the lapsing nudge all read one place.

Lane 1: the sign-up form

The simplest lane for the customer who has a minute. A short web page — a QR code on the counter or a link on the receipt points to it — asks for a name, a phone number, and an optional email. When they submit, the page posts to a Lambda Function URL (a small web address that runs a function directly, with no extra gateway in front). The function writes a new member to the DynamoDB member store keyed by their phone number, sets the balance to zero, and stamps the join date.

If they gave an email, the function sends a one-tap confirm message: “Tap to start getting your balance and rewards by email.” Only after they tap is the email marked confirmed and opted in. This double-check means the shop never emails someone who fat-fingered a stranger’s address into the form, and it keeps the shop on the right side of the rules about marketing email.

Lane 2: staff quick-add (the lane most shops actually use)

Most people sign up because a staff member offered, not because they found a form. So staff get their own small page: type a phone number and a name, tap save, done. It posts to the same Function URL as the form and writes the same kind of record. Email is left blank; if the customer wants their balance by email, staff can add it later or the customer can tap the link in their first balance email.

The quick-add page is deliberately bare — two fields and a save button — because it gets used while a queue is forming. A staff member should be able to enroll a customer in the time it takes to hand over change. Anything that slows that down means fewer people join, which means a weaker program.

Lane 3: auto-enroll on first sale

The most important lane, and the one that quietly does the most work. A sale comes in from the till with a phone number attached — maybe the customer gave it verbally and staff typed it into the till, maybe the till captured it some other way — but the system has never seen that number. Instead of dropping the points on the floor, the earn function creates a member there and then, adds the points, and marks the record as needs-email.

The customer is now a member with a real balance, even though they never filled in a form. The next time a balance email would go out, the system has no address yet, so it does the next best thing: it leaves the points safely banked and waits. When the customer does sign up properly later — via the form or a staff quick-add with the same phone number — the existing record is found and updated, not duplicated, so the points they already earned are right there waiting. No customer ever loses points because the paperwork came after the purchase.

Why the member store stays the source of truth

Three lanes in, but only one place where a member actually lives. That’s a deliberate constraint. Balances change on every sale and have to be exact to the point, so they live in DynamoDB — the system’s own fast, reliable store — not in a doc that two people might edit at the same time. Keying by phone number means a sale, a redemption, and a nudge all find the same person without anyone having to remember a member id. The rules and the email wording live in Drive where the owner can edit them freely; the member balances live where exactness matters. Each thing lives where it belongs.

Next post: how a purchase actually earns points — how the earn function reads the rules, does the math, and picks one of four moves.

All posts