# Frontend Integration Test Guide (Rendi API)

This document helps frontend engineers integrate and test the deployed API.

## Base URL

Production base URL:

```text
https://rendi.co.uk/api
```

All routes below are relative to this base URL.

## Authentication Model

- Auth is token-based using Bearer tokens.
- Send token in header:

```http
Authorization: Bearer <token>
```

- A user has one active token at a time in MVP.
- Logging in again issues a new token and invalidates the previous token.

## Common Headers

```http
Content-Type: application/json
Authorization: Bearer <token>   // required for protected endpoints
```

## Endpoint Summary

Public:
- `POST /signup`
- `POST /login`

Protected:
- `POST /readiness/score`
- `POST /readiness/calculate` (alias)
- `POST /finance/update`
- `POST /readiness/update-finance` (alias)
- `GET /finance/current`
- `GET /readiness/current-finance` (alias)
- `GET /readiness/history?limit=<1..100>`

## Contracts

### 1) Sign up

`POST /signup`

Request:

```json
{
  "name": "Jane Doe",
  "email": "jane@example.com",
  "phone": "+447700900123",
  "password": "secret123"
}
```

- `phone` optional
- `password` min length 8

Success (`201`):

```json
{
  "message": "User registered successfully",
  "token": "<token>",
  "user": {
    "id": 1,
    "name": "Jane Doe",
    "email": "jane@example.com",
    "phone": "+447700900123"
  }
}
```

Common errors:
- `409` duplicate email/phone
- `422` validation

### 2) Login

`POST /login`

Request:

```json
{
  "identifier": "jane@example.com",
  "password": "secret123"
}
```

- `identifier` can be email or phone

Success (`200`):

```json
{
  "message": "Login successful",
  "token": "<token>",
  "user": {
    "id": 1,
    "name": "Jane Doe",
    "email": "jane@example.com",
    "phone": "+447700900123"
  }
}
```

Common errors:
- `401` invalid credentials
- `422` invalid identifier format

### 3) Readiness Score

`POST /readiness/score` (or `/readiness/calculate`)

Requires Bearer token.

Request:

```json
{
  "annualGrossIncome": 45000,
  "savings": 15000,
  "targetPropertyPrice": 250000,
  "targetLocation": "Manchester",
  "monthlyDebtPayments": 200
}
```

- `targetPropertyPrice` required
- `targetLocation` optional

Success (`200`):

```json
{
  "userId": 1,
  "targetLocation": "Manchester",
  "readiness": {
    "score": 58,
    "status": "Getting closer",
    "depositNeeded": 25000,
    "depositGap": 10000,
    "estimatedMonths": 18
  }
}
```

Common errors:
- `401` missing/invalid token
- `422` missing `targetPropertyPrice`

### 4) Update Finance

`POST /finance/update` (or `/readiness/update-finance`)

Requires Bearer token.

Request:

```json
{
  "annualGrossIncome": 52000,
  "savings": 18000,
  "targetLocation": "Leeds",
  "existingCommitments": 350,
  "targetPropertyPrice": 260000
}
```

Rules:
- `annualGrossIncome` required
- `savings` required
- `targetLocation` optional
- `existingCommitments` optional
- `targetPropertyPrice` optional only if already known for this user from earlier score/profile

Behavior:
- Calculates a new score
- Updates user current finance profile
- Adds a new readiness history record

Success (`200`):

```json
{
  "message": "Finance updated and new readiness score calculated",
  "userId": 1,
  "targetLocation": "Leeds",
  "existingCommitments": 350,
  "readiness": {
    "score": 74,
    "status": "Nearly ready",
    "depositNeeded": 26000,
    "depositGap": 8000,
    "estimatedMonths": 13
  }
}
```

Common errors:
- `401` missing/invalid token
- `422` missing required finance fields

### 5) Current Finance Snapshot

`GET /finance/current` (or `/readiness/current-finance`)

Requires Bearer token.

Success (`200`):

```json
{
  "userId": 1,
  "finance": {
    "annualGrossIncome": 52000,
    "savings": 18000,
    "targetPropertyPrice": 260000,
    "targetLocation": "Leeds",
    "existingCommitments": 350
  },
  "latestReadiness": {
    "score": 74,
    "status": "Nearly ready",
    "depositNeeded": 26000,
    "depositGap": 8000,
    "estimatedMonths": 13
  },
  "updatedAt": "2026-03-07 14:24:22"
}
```

Common errors:
- `401` missing/invalid token
- `404` no profile yet

### 6) Readiness History

`GET /readiness/history?limit=10`

Requires Bearer token.

- `limit` optional (default 20, min 1, max 100)

Success (`200`):

```json
{
  "userId": 1,
  "count": 2,
  "history": [
    {
      "id": 4,
      "annualGrossIncome": 64000,
      "savings": 26000,
      "targetPropertyPrice": 300000,
      "targetLocation": "Sheffield",
      "existingCommitments": 300,
      "score": 74,
      "status": "Nearly ready",
      "depositNeeded": 30000,
      "depositGap": 4000,
      "estimatedMonths": 6,
      "createdAt": "2026-03-07T13:49:53+00:00"
    }
  ]
}
```

## Frontend QA Checklist

1. Sign up a new user and store returned token.
2. Call `GET /finance/current` with token and verify it returns `404` before first score/update.
3. Call `POST /readiness/score` and verify score object renders in UI.
4. Call `GET /finance/current` and verify latest finance + latestReadiness fields match previous step.
5. Call `POST /finance/update` with changed values and verify score changes.
6. Call `GET /readiness/history` and verify new result appears at top of list.
7. Login again and verify old token fails with `401`, new token works.
8. Confirm validation errors are surfaced in UI for `422` responses.

## Error Handling Suggestions

- On `401`: clear local token and redirect to auth screen.
- On `422`: map API `error` text to inline field or form-level message.
- On `409`: show duplicate account message during signup.

## Example Frontend Token Storage

- Keep token in memory + secure storage strategy chosen by your app.
- Always attach token for protected endpoints.
- Replace stored token on each successful login.