---
name: dyolink-api-errors
description: Adds or migrates Dyolink API error codes with frontend translations. Use when adding backend validation errors, permission errors, or migrating catch blocks to getUserFacingError.
---

# Dyolink API errors

## Backend

1. Add code to `ErrorCode` in `backend/src/common/errors/error-codes.ts`.
2. Throw with `AppException`:

```typescript
throw new AppException(ErrorCode.MY_CODE, HttpStatus.BAD_REQUEST);
```

3. DTOs: always `{ message: ErrorCode.X }` on class-validator decorators (do not rely on constraint-key fallbacks — e.g. `@Matches` is not always a mobile number).
4. Do **not** throw Nest `BadRequestException('English…')` — unmapped Nest exceptions fall back to HTTP status only (`BAD_REQUEST`, `AUTH_UNAUTHORIZED`, …).
5. Wall-clock rules (working hours, weekday): pass the client **IANA** `timeZone` and use `zoned-civil-time.ts`. Never `Date#getHours()` / `getDay()` on the UTC server.

## Frontend

1. Add key under `"errors"` in `en.json`, `fa.json`, `nl.json` (key = error code string).
2. In components:

```typescript
const tErrors = useTranslations('errors');
// ...
catch (err: unknown) {
  toast.showError(getUserFacingError(err, tErrors, t('fallbackKey')));
}
```

3. Do not use `err.message` or `(err as Error).message` for user display.

## Axios shape

Parsed in `lib/api/client` — expects `{ success: false, error: { code, details? } }`.

See rule: `.cursor/rules/api-errors-i18n.mdc`
