Skip to main content
Version: 2.3

Mnemonic

A Mnemonic defines how tSM generates readable business identifiers (keys/codes) for your entities.
While every record has a technical UUID (id), users and integrations often need meaningful identifiers such as TCK-2025-00456 or ORD-EU-00123.

Where it’s used

  • Business data (e.g., Ticket, Order, Account): generates a Key
  • Registers / code tables (e.g., SLA type, Process type): generates a Code
  • Many public APIs accept both UUID id and business key/code in URLs for CRUD

Concept & Capabilities​

A Mnemonic is a configurable pattern that combines:

  • Constants — prefixes/suffixes ("TCK-", "ORD-")
  • Dynamic variables — entity fields, user/org context, date parts
  • Sequences — auto-incremented numbers with optional restart periods (yearly, monthly, …) and padding

Examples:

EntityPattern (conceptual)Example result
TicketTCK_${yyyy}_${sequence(4)}TCK_2025_0456
OrderORD_${region}_${sequence(5)}ORD_EU_01234
Customer AccountACC_${type}_${yyyyMM}_${sequence(3)}ACC_BUS_202501_007

The generation is unique within scope (global, per type, per region, etc., depending on your SpEL and sequence configuration).


How it works (high level)​

  1. You define a Mnemonic configuration with a SpEL expression in spel.
  2. When a record needs a business key/code, the engine evaluates the expression, reading runtime data and consuming a sequence.
  3. The computed value is stored on the entity (e.g., Ticket.key, or a register code) and used in UI and APIs.

SpEL anatomy (examples)​

#date.format('yyyy') + '-' + #sequence.next('ticket_yearly', 4)
#root.customer?.region + '-' + #sequence.next('order_region_' + #root.customer?.region, 5)
'TCK-' + #date.format('yyyyMM') + '-' + #sequence.next('tck_' + #date.format('yyyyMM'), 4)
  • #root … the current entity/context payload (fields you pass during generation)
  • #date … helper for formatting current time
  • #sequence.next(name, pad) … obtains the next number for a named sequence, left-padded to pad digits
#sequence.next(name, pad)
  • Works with database sequences only. The counter stored in nextSequenceNum is not available to it — see Numbering modes. A configuration that relies on that counter has to be moved to a database sequence before its expression can use #sequence.next().
  • name must be the name of an existing database sequence. Sequences are never created on demand — create one with POST /api/mnemonic/sequence and list them with GET /api/mnemonic/sequence-list. A missing sequence fails key generation with Sequence '…' does not exist in schema '…'.
  • POST /api/mnemonic/sequence puts the name straight into CREATE SEQUENCE, so keep it to lower-case letters, digits and underscores, not starting with a digit. tck_yearly works; TCK-YEARLY and ORD:EU are rejected by the database, while an unquoted upper-case name is not rejected but silently folded — ORD_EU is created as ord_eu.
  • When name is built from runtime values — a region, a customer type, a period — a sequence has to exist for every value the expression can produce, and each of those values has to be a valid lower-case identifier itself. There is no fallback: the first unseen value fails key generation.
  • POST /api/v1/mnemonic-configs/with-sequence creates the sequence too, but derives the name itself — it converts sequenceName to snake case and appends a number if that name is taken, so TCK-YEARLY becomes t_c_k_y_e_a_r_l_y. Read the sequenceName from the response and use that in the expression.
  • pad must be between 0 and 64; anything else fails with ApiConfigurationException. A number longer than pad is never truncated, it only overflows the width.
  • restartPeriod does not apply here — it only restarts the sequence in sequenceName. To restart numbering per period, put the period in the sequence name (ord_2026) and create a sequence for each period before the first record of that period is saved.
  • Drawing through the v2 API — which is what #sequence.next() uses — requires Config.MnemonicConfig.View from the signed-in user. The deprecated GET /api/mnemonic/next_value_spel/code/{code} and GET /api/mnemonic/expression/code/{code} are not protected in 2.3 and draw without it.
#date.format(pattern)

Formats the current time in the business time zone (tsm.locale.timezone, CET by default), so a key rolls over at local midnight. Use #date.format(pattern, zone) to override it.

Exact helper names in your environment may vary—keep the intent: combine context + formatted date/time + a sequence.


Typical flows​

  • On create: generate a business key automatically before save, using entity data (type, priority, region…).
  • Bulk imports: pre-generate or generate-on-insert to keep sequential order and avoid collisions.
  • Scoped sequences: reset numbering per month/year, or per region/customer, by including scope in the sequence name.

Reference​

MnemonicConfig (attributes)​

FieldTypeRequiredRead-onlyDescription / Notes
idUUID––Identifier (not for end-user display).
codeStringYes–Unique ASCII code (no spaces). Stable key used by tools/processes.
nameStringYes–Human-readable name.
descriptionString––Longer help text/tool-tip.
validityFrom/ToDate––Active window for this mnemonic config.
validBool–YesComputed from validity; not stored.
spelStringYes–SpEL expression that builds the final identifier (may reference date/time, payload fields, and sequences).
configTypeString––Links to a ConfigType (grouping for backup/restore, Studio filters).
restartPeriodEnum––Sequence restart policy: PERPETUAL, YEARLY, MONTHLY, DAILY.
sequenceNameString––Database sequence the SEQUENCE placeholder draws from. Filling it in selects the numbering mode — see Numbering modes. Not used by #sequence.next(), which names its own sequence.
nextSequenceNumInteger––Counter used only when sequenceName is empty and the expression uses the SEQUENCE placeholder. Holds the last number handed out; the first generated value is 1. GET /api/v1/mnemonic-configs/{idOrCode}/nextSequenceNum means something different in each mode despite its name: with a sequence it returns the last value + 1, so the number to be issued next; with this counter it returns the counter as stored, i.e. the last number handed out — one less than the next key. POST /api/v1/mnemonic-configs/{idOrCode}/nextSequenceNum/{n} sets it, and means something different in each mode: with the counter the next key is n+1, with a sequence it is n — and the sequence is dropped and recreated.
dataTagsList––Labels for dashboards/filters (e.g., ticketing, ops).
configMap––Free-form metadata used by admin tooling.
localizationDataObject––Translations for name / description.
auditInfoObject––Standard audit metadata.

restartPeriod​

  • PERPETUAL – sequence never resets
  • YEARLY – resets each calendar year
  • MONTHLY – resets each calendar month
  • DAILY – resets each calendar day

Applies only to the sequence named in sequenceName. A configuration whose expression uses #sequence.next() never causes a restart, and one without sequenceName is skipped — but the job restarts any sequence that is some configuration's sequenceName, so a sequence shared by both styles is restarted anyway.

Numbering modes​

The SEQUENCE placeholder — as in 'TCK-' + YEAR + '-' + SEQUENCE — is resolved in one of two ways, decided by whether sequenceName is filled in. (The deprecated GET /api/mnemonic/next_value_spel/code/{code} is the one exception: it always uses the counter.)

Both modes apply to the SEQUENCE placeholder only. #sequence.next() always draws from a database sequence and can never use the counter mode described below.

Database sequence — the production mode. With sequenceName filled in, each key takes the next value of that sequence. Numbering is handled by the database, so it stays correct even when several requests or several instances of the service generate keys at the same time. It is also required for batch generation — with mnemonic pre-fetching enabled, a configuration without sequenceName fails with Sequence name is required for batch generation.

Counter on the configuration — development only. With sequenceName empty, the number comes from nextSequenceNum on the configuration itself: the application reads the value, increments it and writes it back. Every generated key logs Mnemonic generation for development purpose only used. Use table sequence for production use.

danger

Take that warning literally. The increment happens in application code, not in the database, so two concurrent requests can read the same value and produce duplicate keys — the more instances of the service run, the more likely that is.

Use this mode only for a quick try-out on a development environment. Before going live, create a sequence and fill in sequenceName.


Example configurations​

Yearly ticket sequence with prefix and zero-padding

'TCK-' + #date.format('yyyy') + '-' + #sequence.next('tck_yearly', 4)

Region-scoped order sequence

'ORD-' + #root.region + '-' + #sequence.next('ord_' + #root.region, 5)

Customer-type + month scope

'ACC-' + #root.customerType + '-' + #date.format('yyyyMM') + '-' + #sequence.next('acc_' + #root.customerType + '_' + #date.format('yyyyMM'), 3)

Pass the fields you need (e.g., region, customerType) in the generation payload so the expression can use them.


Good Practices​

  • Keep code stable — referenced by processes and admin tools.
  • Design for uniqueness — include enough scope in the sequence name to avoid collisions (e.g., year/month/region).
  • Human-first — prefer short, readable keys; keep noisy data out of the prefix.
  • Reset wisely — use restartPeriod to match business expectations (monthly orders vs. perpetual account numbers). It only drives the sequence in sequenceName; with #sequence.next(), put the period in the sequence name instead.
  • Idempotency — guard against duplicate generation on retries (generate once per record and persist atomically).
  • APIs — expose both UUID and business key/code where practical to simplify integrations and user operations.

See Also​

  • System Settings: ConfigType — organize mnemonic configs for promotion and tooling
  • System Settings: EntityType — where keys/codes are ultimately used and exposed in UI/API
  • Backup / Restorer, tSM Studio — tools that rely on consistent grouping and stable codes