diff --git a/examples/app-showcase/src/datasets/chart-gallery.dataset.ts b/examples/app-showcase/src/datasets/chart-gallery.dataset.ts index 5d41ac7f51..342b0e1afb 100644 --- a/examples/app-showcase/src/datasets/chart-gallery.dataset.ts +++ b/examples/app-showcase/src/datasets/chart-gallery.dataset.ts @@ -41,10 +41,11 @@ export const ShowcaseProjectDataset = defineDataset({ ], measures: [ { name: 'project_count', label: 'Projects', aggregate: 'count' }, - // `budget`/`spent` are currency fields with NO declared currency code, so a - // hardcoded "$" misrepresents the amount (an amount with unspecified - // currency must not show a $ symbol). Use a plain grouped-number format; - // declare a `currency` on the field to get a locale-correct symbol via Intl. + // `budget`/`spent` are currency fields with NO declared currency code. The + // renderer resolves the symbol through the field's `currencyConfig.default- + // Currency` → the tenant `localization.currency` default (ADR-0053); with + // neither set it shows a plain grouped number (never a hardcoded "$"). To + // pin a symbol, set a field `currencyConfig` or a measure `currency`. { name: 'budget_sum', label: 'Total Budget', aggregate: 'sum', field: 'budget', format: '0,0' }, { name: 'spent_sum', label: 'Total Spent', aggregate: 'sum', field: 'spent', format: '0,0' }, ], diff --git a/examples/app-showcase/src/objects/field-zoo.object.ts b/examples/app-showcase/src/objects/field-zoo.object.ts index a405554249..df1bb58d20 100644 --- a/examples/app-showcase/src/objects/field-zoo.object.ts +++ b/examples/app-showcase/src/objects/field-zoo.object.ts @@ -41,7 +41,7 @@ export const FieldZoo = ObjectSchema.create({ // ── Numbers ────────────────────────────────────────────────────────── f_number: Field.number({ label: 'Number', min: 0, max: 1000 }), - f_currency: Field.currency({ label: 'Currency', scale: 2, min: 0 }), + f_currency: Field.currency({ label: 'Currency', scale: 2, min: 0, currencyConfig: { currencyMode: 'fixed', defaultCurrency: 'USD', precision: 2 } }), f_percent: Field.percent({ label: 'Percent', min: 0, max: 100, defaultValue: 50 }), // ── Date & time ────────────────────────────────────────────────────── diff --git a/skills/objectstack-data/rules/field-types.md b/skills/objectstack-data/rules/field-types.md index 163aa155c6..7ab8611b35 100644 --- a/skills/objectstack-data/rules/field-types.md +++ b/skills/objectstack-data/rules/field-types.md @@ -197,12 +197,19 @@ What kind of data? type: 'currency', currencyConfig: { precision: 2, - currencyMode: 'multi', // or 'single' - defaultCurrency: 'USD', + currencyMode: 'fixed', // 'fixed' = one currency for the column; + // 'dynamic' = per-record `{ value, currency }` + defaultCurrency: 'USD', // ISO 4217 }, } ``` +**Currency resolution (ADR-0053).** A displayed amount resolves its symbol +through: the field's own `currencyConfig.defaultCurrency` → the tenant +`localization.currency` default. With neither set, renderers show a plain +grouped number (never a hardcoded `$`). The same chain backs analytics measures +(a measure's explicit `currency` wins over the field/tenant default). + ### Select with Default ```typescript diff --git a/skills/objectstack-i18n/SKILL.md b/skills/objectstack-i18n/SKILL.md index 3a08dc2c29..5d86da329f 100644 --- a/skills/objectstack-i18n/SKILL.md +++ b/skills/objectstack-i18n/SKILL.md @@ -33,6 +33,11 @@ and integration with the I18nService. - You need to **detect missing or stale translations** (coverage analysis). - You are integrating **AI-powered translation suggestions**. - You are implementing **locale-specific formatting** (dates, numbers, currency). + > Workspace regional defaults — reference `timezone`, `locale`, and **`currency`** + > — live in the `localization` SETTINGS (tenant-scoped), are resolved onto every + > request's `ExecutionContext`, and are exposed to the client at + > `GET /api/v1/auth/me/localization`. `localization.currency` is the fallback a + > currency field/measure uses when it omits its own (ADR-0053). - You need to understand **translation file organization strategies** (bundled, per_locale, per_namespace). --- diff --git a/skills/objectstack-ui/SKILL.md b/skills/objectstack-ui/SKILL.md index ddf0a3d72f..283ce5f86e 100644 --- a/skills/objectstack-ui/SKILL.md +++ b/skills/objectstack-ui/SKILL.md @@ -937,6 +937,11 @@ defineDataset({ dimensions: [{ name: 'signed_date', field: 'signed_date', type: 'date', dateGranularity: 'month' }], measures: [{ name: 'signed_count', aggregate: 'count' }], }); +// A monetary measure may declare `currency` (ISO 4217) for a locale-correct +// symbol: `{ name: 'revenue', aggregate: 'sum', field: 'amount', currency: 'USD' }`. +// It resolves measure `currency` → the aggregated field's +// `currencyConfig.defaultCurrency` → the tenant `localization.currency` default +// (ADR-0053). Omit it for non-money measures (count, avg-of-hours). // The widget just selects the dimension by name: { id: 'signed_by_month', type: 'line',