98 lines
3.3 KiB
Markdown
98 lines
3.3 KiB
Markdown
---
|
|
title: TempVerification
|
|
tags: [data-model, mongoose]
|
|
aliases: [Temp Verification, Pending Signup, ITempVerification]
|
|
---
|
|
|
|
# TempVerification
|
|
|
|
Short-lived holding collection for unverified signups. When a user begins registration the candidate data (email, hashed password, first name, last name, role, optional referral code) is saved here together with a verification OTP and its expiry. After the OTP is confirmed the row is promoted to a real [[User]] document and removed. Rows that are never confirmed self-destruct via a TTL index keyed on `emailVerificationCodeExpires`.
|
|
|
|
> [!note] Source
|
|
> `backend/src/models/TempVerification.ts:16` — schema definition
|
|
> `backend/src/models/TempVerification.ts:67` — model export
|
|
|
|
## Schema
|
|
|
|
| Field | Type | Required | Default | Validation | Index | Description |
|
|
| --- | --- | --- | --- | --- | --- | --- |
|
|
| `email` | String | yes | — | lowercase, trim | unique | Candidate email. |
|
|
| `password` | String | no | `""` | — | — | Hashed password (optional for passkey-only flows). |
|
|
| `firstName` | String | yes | — | trim | — | First name. |
|
|
| `lastName` | String | yes | — | trim | — | Last name. |
|
|
| `role` | String | no | `buyer` | enum: `buyer` / `seller` | — | Requested role. |
|
|
| `referralCode` | String | no | — | trim | — | Inviter's referral code. |
|
|
| `emailVerificationCode` | String | yes | — | — | — | OTP. |
|
|
| `emailVerificationCodeExpires` | Date | yes | — | — | TTL (`expireAfterSeconds: 0`) | OTP expiry. |
|
|
| `createdAt` | Date | auto | — | — | — | Mongoose timestamp. |
|
|
| `updatedAt` | Date | auto | — | — | — | Mongoose timestamp. |
|
|
|
|
## Virtuals
|
|
|
|
None defined.
|
|
|
|
## Indexes
|
|
|
|
- Implicit unique index on `email`.
|
|
- `{ emailVerificationCodeExpires: 1 }` with `expireAfterSeconds: 0` — `backend/src/models/TempVerification.ts:65`. MongoDB removes the document automatically once `emailVerificationCodeExpires` passes.
|
|
|
|
> [!note] TTL semantics
|
|
> `expireAfterSeconds: 0` together with the indexed date field means "delete this document as soon as the date in `emailVerificationCodeExpires` is reached".
|
|
|
|
## Pre/Post Hooks
|
|
|
|
None declared.
|
|
|
|
## Instance Methods
|
|
|
|
None defined.
|
|
|
|
## Static Methods
|
|
|
|
None defined.
|
|
|
|
## Relationships
|
|
|
|
- **References**: none.
|
|
- **Referenced by**: none. Promotes into a [[User]] document on successful verification.
|
|
|
|
## State Transitions
|
|
|
|
```mermaid
|
|
stateDiagram-v2
|
|
[*] --> pending : signup started
|
|
pending --> verified : code confirmed
|
|
pending --> expired : TTL purge
|
|
verified --> [*] : promoted to User
|
|
expired --> [*]
|
|
```
|
|
|
|
> [!warning] No persistent "verified" state
|
|
> A `TempVerification` row only ever exists in the `pending` state from the database's point of view. Once verified the row is deleted (and a [[User]] row is created); if not verified it is purged by the TTL index.
|
|
|
|
## Common Queries
|
|
|
|
```ts
|
|
// Look up by email during signup
|
|
TempVerification.findOne({ email: email.toLowerCase() });
|
|
|
|
// Validate OTP
|
|
TempVerification.findOne({
|
|
email: email.toLowerCase(),
|
|
emailVerificationCode: code,
|
|
emailVerificationCodeExpires: { $gt: new Date() },
|
|
});
|
|
|
|
// Replace stale row on a re-attempt
|
|
TempVerification.findOneAndUpdate(
|
|
{ email },
|
|
{ $set: { emailVerificationCode, emailVerificationCodeExpires, ... } },
|
|
{ upsert: true, new: true }
|
|
);
|
|
|
|
// Delete after promotion
|
|
TempVerification.deleteOne({ email });
|
|
```
|
|
|
|
Related: [[User]].
|