> ## Documentation Index
> Fetch the complete documentation index at: https://docs.theroyalglow.in/llms.txt
> Use this file to discover all available pages before exploring further.

# Conventions

> Money, dates, layering, and the API response envelope used across the platform.

# Conventions

<Warning>
  These rules are enforced across the codebase — follow them in any new work. The three that break things hardest if ignored: **money is integer paise (never float)**, **layer imports only point inward**, and **every API response uses the success/error envelope**.
</Warning>

## Money — integer paise

All monetary values are stored and computed as **integer paise** (₹1 = 100
paise). Never use floating point for money.

```ts theme={null}
// ₹1,499.00 is stored as:
const pricePaise = 149900
```

Formatting to rupees happens only at display time, in Indian digit grouping:

```ts theme={null}
formatINR(149900) // → "₹1,499.00"
```

GST is 18% and **inclusive** — back-calculated from the displayed price:

```ts theme={null}
const base = Math.round(inclusivePaise / 1.18)
const gst = inclusivePaise - base
```

## Dates & time

* Stored as `timestamptz` (UTC); displayed in **IST** (UTC+5:30).
* Display format is **DD/MM/YYYY** via `formatDateIN`.
* API payloads use ISO-8601 strings.

## Layer rules (strict)

API routes are **thin orchestrators**: parse → Zod `safeParse` → call business
logic / queries → return JSON. No DB queries live in route handlers' own logic
beyond calling the query layer.

| Name             | Type                           | Description                                                                   |
| ---------------- | ------------------------------ | ----------------------------------------------------------------------------- |
| `Presentation`   | `apps/web/src/app, components` | May import: business, db, types, errors. Must not import: nothing restricted. |
| `API (thin)`     | `apps/web/src/app/api`         | May import: business, db, types, errors. Must not import: UI components.      |
| `Business logic` | `packages/business`            | May import: types, errors. Must not import: db, framework, UI.                |
| `Data access`    | `packages/db`                  | May import: types. Must not import: business, framework, UI.                  |
| `Types`          | `packages/types`               | May import: nothing. Must not import: everything else.                        |

## API response envelope

Every JSON API responds with one of two shapes.

<Tabs>
  <Tab title="Success">
    ```json theme={null}
    {
      "success": true,
      "data": { },
      "meta": { "page": 1, "totalPages": 5, "totalCount": 92 }
    }
    ```

    `meta` is present only on paginated list endpoints.
  </Tab>

  <Tab title="Error">
    ```json theme={null}
    {
      "success": false,
      "error": {
        "code": "VALIDATION_ERROR",
        "message": "Invalid request data",
        "statusCode": 400,
        "requestId": "req_a1b2c3d4e5f6",
        "retryable": false,
        "details": { }
      }
    }
    ```

    * `code` — a stable machine-readable code from the error registry.
    * `requestId` — `req_` + nanoid, for log correlation.
    * `retryable` — present when the caller may safely retry (e.g. transient 5xx).
    * `details` — present on validation errors (field → message map).
  </Tab>
</Tabs>

<Info>
  Background-job routes (`/api/jobs/*`) are the exception: they return a minimal
  `{ processed }` body and a non-2xx status on failure so QStash can retry. They
  do not use the success/error envelope.
</Info>

## Error codes

Codes come from a central registry (`@rgss/errors`). Expand for the common ones — domain-specific codes for booking, membership, invoice, gems, offer, and branch rules are documented on each API page.

<AccordionGroup>
  <Accordion title="VALIDATION_ERROR — 400">
    Zod validation failed. The `details` field carries the field → message map.
  </Accordion>

  <Accordion title="UNAUTHENTICATED — 401">
    No valid session.
  </Accordion>

  <Accordion title="FORBIDDEN — 403">
    Authenticated but insufficient role.
  </Accordion>

  <Accordion title="NOT_FOUND — 404">
    Resource does not exist.
  </Accordion>

  <Accordion title="CONFLICT — 409">
    State conflict (e.g. double-book).
  </Accordion>

  <Accordion title="BUSINESS_RULE_VIOLATION — 409/422">
    A domain rule was violated.
  </Accordion>

  <Accordion title="RATE_LIMITED — 429">
    Too many requests.
  </Accordion>

  <Accordion title="SERVICE_UNAVAILABLE — 503">
    A dependency (e.g. Ably) is not configured.
  </Accordion>

  <Accordion title="INTERNAL_ERROR — 500">
    Unexpected error (retryable).
  </Accordion>
</AccordionGroup>

## Related Pages

<Columns cols={2}>
  <Card title="Data Model" href="/docs/data-model">
    Schema conventions, enums, and ID formats
  </Card>

  <Card title="Error Handling" href="/docs/error-handling">
    The AppError class and handler pattern
  </Card>

  <Card title="API Reference" href="/docs/api-reference">
    Per-endpoint codes and contracts
  </Card>
</Columns>


## Related topics

- [Architecture](/content/docs/architecture.md)
- [Data Model](/content/docs/data-model.md)
- [Frontend](/content/docs/frontend.md)
- [Git Workflow](/content/docs/git-workflow.md)
- [High-Level Design](/content/docs/system-design/high-level-design.md)
