# Account preference

How a User reads and changes their locale, main currency, units and reminder channels, and why the data region is read-only.

## What it does [#what-it-does]

An Account Preference is one row per User (`account_preference`), not per Organization: two Members of one household may use different languages and units. It holds the locale (`pt-BR`, `en-US`, `de-DE`), the main currency totals convert into, the distance unit (`km`/`mi`), the volume unit (`l`/`gal`), the reminder channels (push, email) and the data region (`eu`, `br`, `us`).

The first read creates the row from the device locale the client sends, idempotently: two first reads at once store one row.

| Device language | Locale  | Currency | Distance | Volume | Region |
| --------------- | ------- | -------- | -------- | ------ | ------ |
| `pt-*`          | `pt-BR` | BRL      | km       | l      | br     |
| `de-*`          | `de-DE` | EUR      | km       | l      | eu     |
| anything else   | `en-US` | USD      | mi       | gal    | us     |

Distance is always stored in km and volume in millilitres; the units only change how values are shown. A Vehicle keeps its own currency; totals in the main currency show the rate and its date.

The data region is pinned when the row is created and is not part of `update`: moving an account between regions is a support process (a data migration), so the profile shows it read-only.

## In the app [#in-the-app]

The Profile tab (`M-Perfil`) reads the preference once under the tabs and keeps it in one shared query. Until that read returns, the app formats with the device locale's defaults; then the server value wins, including the app language. Language, main currency, units and reminders each open a sheet that sends only the field it changes; the cache updates at once and rolls back if the server refuses. The rows stay disabled until the first read, so an update never meets `NOT_FOUND`.

Every screen formats amounts, dates, distances and volumes through `useFormat()` (`apps/mobile/src/features/account-preference/account-preference.hooks.ts`), which binds the `@autofolio/domain` formatters to the account locale and units.

## Procedures [#procedures]

| Procedure                                                                                                                 | Who                                   | Failures                                                                                                                                                |
| ------------------------------------------------------------------------------------------------------------------------- | ------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `accountPreference.get` `{ deviceLocale? }`                                                                               | Any signed-in User, for their own row | `UNAUTHORIZED`                                                                                                                                          |
| `accountPreference.update` (partial: `locale`, `currency`, `distanceUnit`, `volumeUnit`, `remindByPush`, `remindByEmail`) | Any signed-in User, for their own row | `UNAUTHORIZED`, `INPUT_VALIDATION` (unknown key such as `dataRegion`, currency outside BRL/EUR/USD/GBP/CHF), `NOT_FOUND` (no row yet: call `get` first) |

Both return the whole preference. No Active Organization is needed.

## Data and isolation [#data-and-isolation]

The `account_preference` table has row-level security keyed by the session's User (`ownedByCurrentUser`). `app_tenant` may insert the row but update only the choice columns, never `data_region` or `user_id`. Deleting the User deletes the row.

## Key files [#key-files]

- [`packages/api/src/features/account-preference/account-preference.contract.ts`](https://github.com/CarlosZiegler/autofolio/blob/main/packages/api/src/features/account-preference/account-preference.contract.ts)
- [`packages/api/src/features/account-preference/account-preference.service.ts`](https://github.com/CarlosZiegler/autofolio/blob/main/packages/api/src/features/account-preference/account-preference.service.ts)
- [`apps/mobile/src/features/account-preference/account-preference.hooks.ts`](https://github.com/CarlosZiegler/autofolio/blob/main/apps/mobile/src/features/account-preference/account-preference.hooks.ts)
- [`apps/mobile/src/features/settings/settings.profile.screen.tsx`](https://github.com/CarlosZiegler/autofolio/blob/main/apps/mobile/src/features/settings/settings.profile.screen.tsx)
- [`packages/db/src/schema/preferences.ts`](https://github.com/CarlosZiegler/autofolio/blob/main/packages/db/src/schema/preferences.ts)

