---
title: Address
tags: [data-model, mongoose]
aliases: [Shipping Address, IAddress]
---

# Address

User-owned address book entry. Each row carries the recipient name, optional phone, full address text, city/state/country/zip, an address type (`Home` / `Office` / `Other`), and a `primary` flag. A pre-save hook enforces a single primary address per user by demoting the user's other addresses when the saving document is primary.

> [!note] Source
> `backend/src/models/Address.ts:20` — schema definition
> `backend/src/models/Address.ts:89` — model export

## Schema

| Field | Type | Required | Default | Validation | Index | Description |
| --- | --- | --- | --- | --- | --- | --- |
| `userId` | ObjectId → [[User]] | yes | — | — | yes (single + compound) | Owner. |
| `name` | String | yes | — | trim | — | Recipient name. |
| `phoneNumber` | String | no | — | trim | — | Recipient phone. |
| `fullAddress` | String | yes | — | trim | — | Address line. |
| `city` | String | yes | — | trim | — | City. |
| `state` | String | yes | — | trim | — | State / province. |
| `country` | String | yes | — | trim | — | Country. |
| `zipCode` | String | no | — | trim | — | Postal code. |
| `addressType` | String | no | `Home` | enum: `Home` / `Office` / `Other` | — | Address type label. |
| `primary` | Boolean | no | `false` | — | yes (compound, desc) | Whether this is the default address. |
| `createdAt` | Date | auto | — | — | — | Mongoose timestamp. |
| `updatedAt` | Date | auto | — | — | — | Mongoose timestamp. |

## Virtuals

None defined.

## Indexes

- `{ userId: 1 }` — from field-level `index: true` at `backend/src/models/Address.ts:25`.
- `{ userId: 1, primary: -1 }` — `backend/src/models/Address.ts:75`.

## Pre/Post Hooks

| Hook | Behaviour |
| --- | --- |
| `pre('save')` (`backend/src/models/Address.ts:78`) | If the document being saved is `primary: true`, demotes (`primary: false`) every other address belonging to the same `userId`. |

## Instance Methods

None defined.

## Static Methods

None defined.

## Relationships

- **References**: [[User]] (`userId`).
- **Referenced by**: none directly. Address text is also embedded into [[PurchaseRequest]] `deliveryInfo.deliveryAddress` at request time, denormalised so historical requests do not change if the address book changes later.

## State Transitions

No status field. The boolean `primary` flag follows a simple at-most-one invariant maintained by the pre-save hook.

## Common Queries

```ts
// User's address book
Address.find({ userId }).sort({ primary: -1, updatedAt: -1 });

// Primary address
Address.findOne({ userId, primary: true });

// Set a new primary (hook handles demotion)
const addr = await Address.findById(id);
addr.primary = true;
await addr.save();

// Delete an address
Address.deleteOne({ _id, userId });
```

Related: [[User]], [[PurchaseRequest]].
