## 1. High-Level Overview

This document describes a modular loyalty platform that supports:

- Stamp-based loyalty (e.g., coffee shops, barbers)
- Points-based loyalty (e.g., clothing stores, restaurants)
- Google Wallet passes (JSON + API)
- Apple Wallet passes (`.pkpass` files)
- Staff PIN system for fraud prevention
- QR-based flows for visits and purchases
- Email collection and basic CRM

The architecture is designed to be extensible: you can add tiers, referrals, coupons, gift cards, and more without redesigning the core.

## 2. Backend Architecture

### 2.1 Core Modules

- Auth & Merchant Management: merchants, stores, staff PINs, billing hooks.
- Customer & Pass Management: customers, pass objects, Wallet IDs.
- Loyalty Engine: stamp logic and points logic.
- QR Engine: static QR codes per store, scan endpoints.
- Dashboard API: analytics, customer lists, rewards, exports.
- Wallet Integrations: Google Wallet and Apple Wallet modules.

### 2.2 Folder Structure

    backend/
      app/
        main.py
        config.py
        dependencies.py

        api/
          merchants.py
          stores.py
          passes.py
          stamps.py
          points.py
          qr.py
          dashboard.py
          apple_passes.py

        core/
          google_wallet.py
          loyalty_engine/
            stamps.py
            points.py
          qr_generator.py
          apple_wallet/
            __init__.py
            signer.py
            generator.py
            templates/
              loyalty_pass.json
              images/
                icon.png
                logo.png
                strip.png

        models/
          merchant.py
          store.py
          customer.py
          pass_object.py
          stamp_event.py
          points_event.py
          apple_device_registration.py

        db/
          base.py
          session.py
          migrations/

        utils/
          security.py
          id_generator.py
          validators.py

      requirements.txt

## 3. Data Model

### 3.1 Merchant vs Store

Merchant = business entity (e.g., “CoffeeLux”) Store = specific location/branch (e.g., “CoffeeLux Gare”).

#### Merchant

Field | Type
--- | ---
id | UUID
name | string
email | string
password_hash | string
created_at | datetime

#### Store

Field | Type
--- | ---
id | UUID
merchant_id | FK → Merchant
name | string
qr_code_url | string
loyalty_type | `"stamps"` | `"points"` | `"hybrid"`
staff_pin_hash | string (hashed)

#### Customer

Field | Type
--- | ---
id | UUID
email | string (nullable)
phone | string (nullable)
email_consent | bool
email_consent_at | datetime (nullable)
created_at | datetime

#### PassObject

Field | Type
--- | ---
id | UUID
customer_id | FK → Customer
store_id | FK → Store
google_pass_id | string (nullable)
apple_serial | string (nullable)
apple_auth_token | string (nullable)
stamp_count | int
points_balance | int
reward_unlocked | bool
last_stamp_at | datetime (nullable)
last_points_at | datetime (nullable)

#### StampEvent

Field | Type
--- | ---
id | UUID
pass_id | FK → PassObject
store_id | FK → Store
timestamp | datetime

#### PointsEvent

Field | Type
--- | ---
id | UUID
pass_id | FK → PassObject
store_id | FK → Store
points_added | int
amount | decimal (optional)
timestamp | datetime

#### AppleDeviceRegistration

Field | Type
--- | ---
id | UUID
device_id | string
pass_serial | string
push_token | string
updated_at | datetime

## 4. Core Flows

### 4.1 Creating a Pass (Onboarding)

1. Customer scans a QR code or visits a link.
2. Page asks for optional data:
   - Name (optional)
   - Email (optional, with consent checkbox)
   - Phone (optional)
3. Backend:
   - Creates or finds Customer.
   - Creates PassObject for the chosen store.
   - Generates Google Wallet link and/or Apple Wallet `.pkpass`.
4. Customer taps “Add to Google Wallet” or “Add to Apple Wallet”.

### 4.2 Stamping a Pass (Visits)

Endpoint: `POST /stamp/{store_id}`

1. Customer scans store QR: `https://yourdomain.com/stamp/{store_id}`.
2. Page identifies the customer’s pass (via login, token, or Wallet ID).
3. Staff enters a PIN on the customer’s device.
4. Backend:
   - Validates staff PIN.
   - Checks cooldown (e.g., 1 stamp per X minutes).
   - Increments `stamp_count`.
   - Logs a StampEvent.
   - Updates Google Wallet and Apple Wallet passes.
5. Customer sees updated stamp count.

### 4.3 Adding Points (Purchases)

Endpoint: `POST /points/{store_id}`

    {
      "pass_id": "abc123",
      "amount": 59.90,
      "staff_pin": "4821"
    }

1. Staff enters purchase amount and PIN.
2. Backend:
   - Validates staff PIN.
   - Converts amount → points (e.g., €1 = 1 point).
   - Updates `points_balance`.
   - Logs a PointsEvent.
   - Updates Wallet passes.

### 4.4 Reward Logic

Implemented in `loyalty_engine/stamps.py` and `loyalty_engine/points.py`.

- Stamps: reward after N stamps.
- Points: reward at thresholds (e.g., 100, 250, 500 points).
- Hybrid: store can use both stamps and points.

## 5. Staff PIN System & Anti-Fraud

### 5.1 Staff PIN Concept

Each store has one or more staff PINs. A stamp or points addition is only valid if a correct PIN is provided.

Example request:

    POST /stamp/{store_id}
    {
      "pass_id": "abc123",
      "staff_pin": "4821"
    }

### 5.2 Implementation

- Store table: `staff_pin_hash` (hashed with bcrypt/argon2).
- Staff enters PIN on customer’s device after a purchase/visit.
- Backend compares provided PIN with hash.

### 5.3 Additional Anti-Fraud Layers

- Cooldown: 1 stamp per X minutes per pass.
- Device fingerprinting: optional (IP, user agent, cookies).
- Reward state checks: don’t stamp a full card.
- Staff PIN rotation: merchants can change PIN periodically.
- Attempt limits: block after N wrong PIN attempts.

The QR code itself never directly grants a stamp or points. It only opens a URL; the backend decides whether to award anything.

## 6. Email Collection & GDPR Considerations

### 6.1 When to Collect Email

- During pass creation: best moment, right after QR scan.
- On reward redemption: “Want your next reward reminder by email?”
- On progress view: small banner: “Add your email to get reward reminders.”

### 6.2 Data Model

- `Customer.email`
- `Customer.email_consent`
- `Customer.email_consent_at`

### 6.3 GDPR-Friendly Flow (EU/Luxembourg)

- Use an explicit checkbox:
  “I agree to receive loyalty updates and promotions.”
- Do not pre-check the box.
- Store consent timestamp.
- Provide unsubscribe link in emails.

### 6.4 Usage

- Reward notifications (“Your reward is ready”).
- Progress nudges (“You’re 1 stamp away”).
- Promotions and new collection announcements.
- Birthday offers (if DOB is collected).

## 7. Features Beyond Stamps & Points

### 7.1 Reward Types

- Tiered loyalty levels: Bronze, Silver, Gold based on spend or visits.
- Cashback / store credit: earn balance redeemable in-store.
- Birthday rewards: automatic bonuses around customer’s birthday.
- Referral rewards: invite friends, both get points or discounts.
- Hybrid models: stamps + points + referrals.

### 7.2 Coupons, Vouchers, Gift Cards

- Digital coupons (percentage or fixed amount).
- Digital gift cards with balance.
- Time-limited offers (weekend-only, seasonal).

### 7.3 Marketing & Communication

- Email campaigns.
- SMS campaigns.
- Wallet-based notifications (pass updates, messages).

### 7.4 Analytics & CRM

- Visit frequency, average spend, redemption rates.
- Customer lifetime value.
- New vs returning customers.
- Store-level and staff-level performance.
- Basic CRM: customer profiles, segmentation.

### 7.5 Advanced Options

- Receipt scanning with OCR.
- POS integration (automatic points and redemptions).
- Gamification (spin-the-wheel, scratch cards, challenges).
- Paid memberships / VIP subscriptions.

## 8. Google Wallet Integration

### 8.1 Core Concepts

- Google Wallet uses Passes API with JSON-based classes and objects.
- You define a loyalty class and create pass objects per customer.
- Updates are done via API calls (patching fields like points, stamps, messages).

### 8.2 Required Setup

- Google Cloud project.
- Wallet API enabled.
- Service account with JSON key.
- Issuer ID and loyalty class definition.

### 8.3 Backend Responsibilities

- Create pass objects for new customers.
- Store `google_pass_id` in PassObject.
- Update pass when stamps/points change.
- Optionally send messages or promotions via pass updates.

### 8.4 Example Endpoint Sketch

    @router.post("/passes/create")
    async def create_pass(data: PassCreateRequest, db: Session = Depends(get_db)):
        customer = get_or_create_customer(db, data)
        pass_obj = get_or_create_pass(db, customer, data.store_id)

        google_link = google_wallet.create_pass(pass_obj)
        return {"add_to_wallet_url": google_link}

## 9. Apple Wallet Integration

### 9.1 Core Difference

Apple Wallet uses signed `.pkpass` files instead of a JSON API. A `.pkpass` is a ZIP containing:

- `pass.json` – pass data
- Images – logo, icon, strip
- `manifest.json` – SHA-1 hashes of all files
- `signature` – signed manifest using your certificate

### 9.2 Requirements

- Apple Developer Program membership.
- Pass Type ID (e.g., `pass.com.yourbrand.loyalty`).
- Pass certificate (`.p12`).
- Push notification certificate for Wallet updates.

### 9.3 Pass Template (pass.json)

    {
      "formatVersion": 1,
      "passTypeIdentifier": "pass.com.yourbrand.loyalty",
      "teamIdentifier": "ABCDE12345",
      "organizationName": "Your Brand",
      "serialNumber": "{{serial}}",
      "description": "Loyalty Card",
      "logoText": "Your Brand",
      "foregroundColor": "rgb(255,255,255)",
      "backgroundColor": "rgb(0,0,0)",
      "storeCard": {
        "primaryFields": [
          {
            "key": "points",
            "label": "Points",
            "value": "{{points}}"
          }
        ],
        "secondaryFields": [
          {
            "key": "stamps",
            "label": "Stamps",
            "value": "{{stamps}}"
          }
        ]
      },
      "barcode": {
        "format": "PKBarcodeFormatQR",
        "message": "{{pass_id}}",
        "messageEncoding": "iso-8859-1"
      },
      "webServiceURL": "https://yourdomain.com/apple/updates",
      "authenticationToken": "{{auth_token}}"
    }

### 9.4 pkpass Generation Flow

1. Load `loyalty_pass.json` template.
2. Inject dynamic values (serial, points, stamps, auth token, etc.).
3. Add required images (icon, logo, strip).
4. Create `manifest.json` with SHA-1 hashes of all files.
5. Sign manifest with your `.p12` certificate and Apple’s WWDR cert.
6. Zip everything into a `.pkpass` file.
7. Return `.pkpass` from endpoint `GET /passes/apple/{pass_id}`.

### 9.5 Device Registration & Updates

Apple Wallet uses a push + pull model for updates:

1. Customer adds pass → Apple sends device registration to your backend.
2. You store device ID, pass serial, and push token in `AppleDeviceRegistration`.
3. When stamps/points change:
   - You send a push notification to Apple using the push token.
   - Apple notifies the device; Wallet calls your `webServiceURL`.
   - Device fetches updated pass data from `GET /apple/updates/{pass_type}/{serial}`.

### 9.6 Data Model Additions

- `PassObject.apple_serial`
- `PassObject.apple_auth_token`
- `AppleDeviceRegistration` table for device + push tokens.

### 9.7 What Stays the Same

- Merchant, Store, Customer, PassObject core structure.
- Stamp and points logic.
- QR flows and staff PIN system.
- Dashboard and analytics.

## 10. Multi-Wallet Strategy

Your platform supports both Google Wallet and Apple Wallet by treating them as two output formats for the same underlying PassObject.

- Google: store `google_pass_id`, update via API.
- Apple: store `apple_serial` and `apple_auth_token`, update via push + web service.

Whenever stamps or points change, you:

- Patch the Google Wallet pass (if it exists).
- Trigger Apple Wallet update (if Apple pass exists).

The merchant and store don’t need to care about the technical differences—your backend abstracts it away.

## 11. Deployment & Stack

- Backend: FastAPI (Python).
- Database: PostgreSQL (or MySQL), with migrations.
- Caching / rate limiting: Redis (optional but recommended).
- Web server: Nginx or similar reverse proxy.
- Containerization: Docker for reproducible deployments.
- Security: HTTPS via Cloudflare or Let’s Encrypt.
- Cloud: Any provider; Google Cloud is convenient for Wallet API.

## 12. MVP vs Future Phases

### 12.1 MVP Scope

- Merchant + Store management.
- Customer + PassObject models.
- Stamp-based loyalty with staff PIN.
- Points-based loyalty for clothing stores.
- Google Wallet integration.
- Apple Wallet integration (basic, without advanced segmentation).
- Basic dashboard: customers, stamps, points, rewards.
- Email collection with consent.

### 12.2 Phase 2 Ideas

- Tiers (Bronze/Silver/Gold).
- Referrals and invite links.
- Coupons, vouchers, and gift cards.
- Gamification (spin-the-wheel, scratch cards).
- Receipt scanning and POS integration.
- Paid memberships / VIP programs.

## 13. Closing Notes

The key design choice is that you do not redesign the system when adding:

- Points on top of stamps.
- Apple Wallet on top of Google Wallet.
- New reward types (tiers, referrals, coupons).

You extend the same core models and flows with additional modules and fields, keeping the architecture modular and future-proof.