---
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]].
