# Email OTP Flow — Pseudocode

File: `app/Http/Controllers/V3/B2C/English/CustomerController.php`

---

## `sendEmailOTP(email)`

```
FUNCTION sendEmailOTP(email):

    # 1. Generate a 6-digit OTP
    otp = LoginQuery.generateOTP(email)
        # returns "091081" if email == "ram@quitsure.app"
        # else returns random number between 100000 and 999999

    # 2. Save email + OTP into the user's session
    userData = Session.get("CustomerData", default = [])
    userData["LocalData"]["vEmail"] = email
    userData["LocalData"]["OTP"]    = otp
    Session.put("CustomerData", userData)

    # 3. Mark all previous active OTPs for this email as expired
    LoginQuery.expirePreviousOTP(email)
        # SQL: UPDATE tbl_Login
        #      SET bExpired = 1
        #      WHERE vEmail = email AND bExpired = 0

    # 4. Insert the new OTP into tbl_Login
    LoginQuery.create({
        vEmail:       email,
        vOTP:         otp,
        dDateCreated: now()
    })

    # 5. Send the OTP via Postmark "otp" template
    PostmarkService.sendPredefinedTemplate(
        toEmail:    email,
        templateKey: "otp",
        data:       { otp_code: otp }
    )

    RETURN  # void
```

---

## `resendEmailOTP(request)`

Route: `POST /web/v3/eng/email/resend`

```
FUNCTION resendEmailOTP(request):

    # 1. Validate the request body
    validator = Validator.make(request.all(), rules = {
        vEmail: "required | email:filter"
    })

    # 2. Normalize the email
    email = lowercase(trim(request.input("vEmail")))

    # 3. If validation failed, log the error and return failure JSON
    IF validator.fails():
        logError({
            class:    self,
            function: "resendEmailOTP",
            message:  "Please submit valid information",
            postdata: email,
            url:      request.url()
        })
        RETURN JSON {
            status:  false,
            message: translate("validation.submit_valid_information")
        }
    END IF

    # 4. Look up the most recent active OTP for this email
    data = LoginQuery.getActiveOTP(email)
        # SQL: SELECT * FROM tbl_Login
        #      WHERE vEmail = email AND bUsed = 0 AND bExpired = 0
        #      LIMIT 1

    # 5. Branch: re-send existing OTP, or issue a brand new one
    IF data EXISTS:
        # Existing OTP still active → resend the same code
        PostmarkService.sendPredefinedTemplate(
            toEmail:    email,
            templateKey: "otp",
            data:       { otp_code: data.vOTP }
        )
    ELSE:
        # No active OTP → generate + persist + email a fresh one
        sendEmailOTP(email)
    END IF

    # 6. Always return success
    RETURN JSON {
        status:  true,
        message: "success"
    }
```

---

## Combined flow (caller's view)

```
USER clicks "Resend OTP"
        │
        ▼
POST /web/v3/eng/email/resend  { vEmail: "user@example.com" }
        │
        ▼
resendEmailOTP(request)
        │
        ├── validation fails ──► return { status: false }
        │
        ├── active OTP exists ──► email same OTP via Postmark
        │                          │
        │                          ▼
        │                       return { status: true }
        │
        └── no active OTP ─────► sendEmailOTP(email)
                                   │
                                   ├── generate new OTP
                                   ├── store in session
                                   ├── expire old OTPs in DB
                                   ├── insert new OTP in DB
                                   └── email new OTP via Postmark
                                   │
                                   ▼
                                return { status: true }
```

---

## Dependencies at a glance

| Used | What it does |
|---|---|
| `LoginQuery.generateOTP(email)` | Returns a 6-digit OTP (fixed `091081` for `ram@quitsure.app`). |
| `LoginQuery.expirePreviousOTP(email)` | `UPDATE tbl_Login SET bExpired = 1 WHERE vEmail = ? AND bExpired = 0`. |
| `LoginQuery.create(data)` | Inserts a new OTP row into `tbl_Login`. |
| `LoginQuery.getActiveOTP(email)` | Returns latest row where `bUsed = 0 AND bExpired = 0`, else `null`. |
| `PostmarkService.sendPredefinedTemplate(...)` | Sends an email via the Postmark `otp` template. |
| `Session ("CustomerData")` | Stores `LocalData.vEmail` and `LocalData.OTP` for the verify step. |

---

## Notes

- OTP is stored in **plaintext** in both DB and session.
- Postmark call is **synchronous** — it blocks the HTTP response.
- There is **no rate limiting** on either method.
- `resendEmailOTP` always returns HTTP 200; check the `status` field for success/failure.
- Identical method bodies also live in `V3/B2C/BaseCustomerController.php`, `V2/B2C/BaseCustomerController.php`, and `V2/B2B/BasePartnerController.php` — keep them in sync.
