Skip to content

feat(auth): dedicated EmailOtp model - #60

Open
Tijesunimi004 wants to merge 1 commit into
ShadeProtocol:mainfrom
Tijesunimi004:fix/dedicated-email-otp-model
Open

feat(auth): dedicated EmailOtp model#60
Tijesunimi004 wants to merge 1 commit into
ShadeProtocol:mainfrom
Tijesunimi004:fix/dedicated-email-otp-model

Conversation

@Tijesunimi004

Copy link
Copy Markdown

Closes #28

What changed

Email OTP verification stored the hashed code and expiry as emailOtp / emailOtpExpiresAt columns on Merchant, overwritten in place on each issue/resend. This moves OTP storage into its own EmailOtp model, shaped like the existing AuthNonce model: one row per generated code, spent by stamping usedAt rather than nulling a shared field.

Schema

  • New EmailOtp model: id, merchantId (FK to Merchant), codeHash, expiresAt, usedAt?, createdAt, with an index on (merchantId, createdAt).
  • Removed Merchant.emailOtp and Merchant.emailOtpExpiresAt.
  • FK uses onDelete: Cascade — OTP rows are ephemeral and should not block a merchant delete. AuthNonce uses SET NULL only because its merchantId is nullable; here it is required, matching the issue's schema.
  • Migration drops any in-flight codes. Per the issue this is acceptable — nothing depends on preserving them.

Services

  • issueEmailOtp inserts a new EmailOtp row instead of writing to Merchant.
  • verifyEmailOtp looks up the merchant's most recent unused row, checks expiry then hash, stamps usedAt on success, and sets Merchant.emailVerified. Wrong / expired / missing codes return the same 400s as before.
  • resendEmailOtp enforces the one-per-minute limit by querying for an EmailOtp row created within the last 60s, instead of deriving "last sent" from expiresAt - 10min.
  • registerMerchant now calls issueEmailOtp rather than duplicating the generate/hash/send logic inline.
  • No change to email.service.ts.

Tests

  • Rewrote otp.services and auth.email-otp suites against the new model, including expired and already-used rows.
  • Updated the registerMerchant suites to assert issueEmailOtp is invoked.
  • Dropped the now-removed emailOtp fields from shared merchant fixtures.

Full suite: 507 passing.

Replace the emailOtp/emailOtpExpiresAt pair on Merchant with an EmailOtp
model shaped like AuthNonce: one row per generated code, hashed, spent by
stamping usedAt. This gives OTP history and makes the "1 resend per
minute" rule a plain query for a recent row instead of arithmetic against
a single mutable expiry field.

- schema: add EmailOtp (merchantId FK, codeHash, expiresAt, usedAt,
  createdAt; index on merchantId+createdAt); drop the two Merchant fields
- otp.services: issueEmailOtp inserts a row; verifyEmailOtp matches the
  newest unused row, checks expiry and hash, stamps usedAt, then flips
  Merchant.emailVerified; resendEmailOtp rate-limits via an EmailOtp
  createdAt lookup
- merchant.services: registerMerchant delegates OTP issuance to
  issueEmailOtp instead of duplicating generate/hash/send inline
- migration drops in-flight codes, which is acceptable

Response codes for wrong, expired, and already-used codes are unchanged.
Copilot AI lite review requested due to automatic review settings August 30, 2026 18:31

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@coderabbitai

coderabbitai Bot commented Aug 30, 2026

Copy link
Copy Markdown
Contributor

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: b92af415-2f1d-419d-bbf8-73ef663c6e0b


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Dedicated Email OTP Model (Corrects emailOTP Merchant-Field Approach)

2 participants