# Cashi Backend API (Dashboard)

## Base URLs

- **Local**: `http://localhost:3000`
- **Swagger UI**: `/docs` (or `/{SWAGGER_PATH}`)
- **OpenAPI JSON**: `/docs-json` (or `/{SWAGGER_PATH}-json`)

## Authentication

- **Header**: `Authorization: Bearer <accessToken>`
- **JWT expiry**: **365 days** (default `JWT_EXPIRES_IN=365d`)
- **Logout revocation**: `POST /auth/logout` increments `user.tokenVersion`. Any old JWT with mismatched `ver` is rejected.

## Roles and shop linkage rules

- **SUPERADMIN**
  - Bootstraps the first superadmin (one-time)
  - Seeds plans (basic/growth/pro)
  - Creates **ADMIN + SHOP** in one call
- **ADMIN**
  - Creates **SUBADMIN** for their shop
  - Creates **CUSTOMER (USER)** for their shop
- **SUBADMIN**
  - Can login (OTP or password) and access dashboard (extend permissions as needed)
- **USER (Customer)**
  - Logs in via OTP (phone)

**Important**:
- A **Shop is created when a SUPERADMIN creates an ADMIN**.
- **SUBADMIN and USER are always linked to the Admin’s shop** (`user.shopId`).
- **OTP login is allowed only for users that already exist in DB** (so every OTP-login user is already linked to a shop).

## Plan codes (backend)

`PlanCode`: `BASIC | GROWTH | PRO`

Plan fields returned by API:
- `priceMonthly` (integer): `0`, `999`, `2499`
- `currency`: `INR`
- `features`: list of strings (backend-defined)

---

## System

### Health

**GET** `/health`

Response:

```json
{
  "status": "ok",
  "uptimeSeconds": 123.45,
  "timestamp": "2026-04-01T00:00:00.000Z"
}
```

### Hello (starter)

**GET** `/`

Response: `Hello World!`

---

## Plans

### List plans

**GET** `/plans`

Response (example):

```json
[
  {
    "id": "ck...",
    "code": "BASIC",
    "name": "Basic",
    "priceMonthly": 0,
    "currency": "INR",
    "features": ["Core billing", "Shop profile", "Role-based access"]
  }
]
```

### Seed default plans (basic/growth/pro)

**POST** `/plans/seed-defaults`  
Auth: **SUPERADMIN**

Response:

```json
{
  "seeded": 3,
  "plans": [
    { "id": "ck...", "code": "BASIC", "name": "Basic" }
  ]
}
```

---

## Auth

### Bootstrap first superadmin (one-time)

**POST** `/auth/bootstrap/superadmin`

Body:

```json
{
  "email": "super@cashi.com",
  "password": "StrongPass@123",
  "phone": "+919999999999"
}
```

Notes:
- Works **only if no SUPERADMIN exists**.

Response:

```json
{
  "accessToken": "eyJ...",
  "tokenType": "Bearer",
  "expiresIn": "365d"
}
```

### Login (email + password)

**POST** `/auth/login/password`

Body:

```json
{
  "email": "admin@cashi.com",
  "password": "StrongPass@123"
}
```

Response:

```json
{
  "accessToken": "eyJ...",
  "tokenType": "Bearer",
  "expiresIn": "365d"
}
```

### Request OTP (phone)

**POST** `/auth/otp/request`

Body:

```json
{ "phone": "+919999999999" }
```

Response:
- Production:

```json
{ "otpSent": true }
```

- Non-production (dev convenience):

```json
{ "otpSent": true, "devOtp": "123456" }
```

### Verify OTP (phone)

**POST** `/auth/otp/verify`

Body:

```json
{ "phone": "+919999999999", "code": "123456" }
```

Response:

```json
{
  "accessToken": "eyJ...",
  "tokenType": "Bearer",
  "expiresIn": "365d"
}
```

### Logout (revokes existing JWTs)

**POST** `/auth/logout`  
Auth: any logged-in user

Response:

```json
{ "loggedOut": true }
```

### Current user

**GET** `/auth/me`  
Auth: any logged-in user

Response (example):

```json
{
  "id": "ck...",
  "email": "admin@cashi.com",
  "role": "ADMIN",
  "shopId": "ck...",
  "tokenVersion": 0
}
```

---

## Users + Shop creation

### Get single user details

**GET** `/users/:id`  
Auth: any logged-in user

Authorization rules:
- **SUPERADMIN**: can fetch **any** user
- **ADMIN/SUBADMIN**: can fetch only users within the **same shop**
- **USER**: can fetch **only self** (their own `:id`)

Response (example):

```json
{
  "id": "ck...",
  "role": "ADMIN",
  "email": "admin@cashi.com",
  "phone": "+919999999999",
  "shopId": "ck...",
  "tokenVersion": 0,
  "createdAt": "2026-04-01T00:00:00.000Z",
  "updatedAt": "2026-04-01T00:00:00.000Z",
  "shop": {
    "id": "ck...",
    "name": "Cashi Store",
    "address": "123 Street",
    "city": "Mumbai",
    "state": "MH",
    "pincode": "400001",
    "gstNo": "27AAAAA0000A1Z5",
    "plan": {
      "id": "ck...",
      "code": "GROWTH",
      "name": "Growth",
      "priceMonthly": 999,
      "currency": "INR",
      "features": ["Everything in Basic", "Advanced reports", "Customer management"]
    }
  }
}
```

### SUPERADMIN creates Admin + Shop

**POST** `/users/admins`  
Auth: **SUPERADMIN**

Body:

```json
{
  "email": "admin@cashi.com",
  "password": "StrongPass@123",
  "phone": "+919999999999",
  "shop": {
    "name": "Cashi Store",
    "address": "123 Street",
    "city": "Mumbai",
    "state": "MH",
    "pincode": "400001",
    "gstNo": "27AAAAA0000A1Z5",
    "planCode": "GROWTH"
  }
}
```

Response (example):

```json
{
  "admin": { "id": "ck...", "email": "admin@cashi.com", "role": "ADMIN", "phone": "+919999999999" },
  "shop": { "id": "ck...", "name": "Cashi Store", "city": "Mumbai", "state": "MH", "pincode": "400001" }
}
```

Notes:
- Requires plan to exist. Seed plans first via `POST /plans/seed-defaults`.

### ADMIN creates Subadmin (linked to admin’s shop)

**POST** `/users/subadmins`  
Auth: **ADMIN**

Body:

```json
{
  "email": "subadmin@cashi.com",
  "password": "StrongPass@123",
  "phone": "+919888888888"
}
```

Response includes `shopId`.

### ADMIN creates Customer (USER) (linked to admin’s shop)

**POST** `/users/customers`  
Auth: **ADMIN**

Body:

```json
{
  "phone": "+919777777777",
  "email": "customer@cashi.com"
}
```

Response includes `shopId`.

---

## Suggested frontend bootstrap sequence

1. `POST /auth/bootstrap/superadmin`
2. `POST /plans/seed-defaults`
3. `POST /users/admins` (choose planCode)
4. Admin/Subadmin login:
   - Dashboard (email/password): `POST /auth/login/password`
   - OTP: `POST /auth/otp/request` → `POST /auth/otp/verify`

