Builds on 0342 (gapless
sequences). Settles its open point on the time zone of a yearly series and turns its two planned
gen checks into checks that run.
Context
A yearly series (INV-{year}-{n:06}) starts again at 1 each year, and the year is read at the moment a number is
taken. SequenceService.next read it in the time zone the caller passed, which in an action is the user’s own
(ctx.timeZone): two cashiers of one legal entity in different zones could number the same night in two different
years. The year belongs to the legal entity’s calendar, which is configuration, not code. ADR 0342 also planned two gen
checks: a document-number field without a Sequence, and a migration that creates a Postgres SEQUENCE. No field
marker for a document number exists in @stackra/model yet, so the first cannot be checked; the second can, and the
sequence’s one home (database/sequences/) can too.
Decision
- The time zone is the series owner’s setting.
@stackra/database/contractshas aSequenceTimeZoneport:timeZoneOf(key, scope, series)answers the IANA zone of one series, or nothing. The product that owns the series binds a driver that reads its own settings (for example a legal entity’s numbering time zone); the database never reads a setting. Gen’s boot connects the bound driver (connectSequenceTimeZone). When a driver answers, its zone governs the year fornextandreserve; when none is bound or the setting is unset, the caller’s zone governs. - A sequence has one home. Gen refuses a
Sequenceclass outsidedatabase/sequences/<name>.sequence.ts(sequence_misplaced). - No Postgres sequence. The migration compiler refuses a raw
CREATE SEQUENCE(anyTEMPorUNLOGGEDform): a document number is aSequence, an id is a public id, and a rolled-back transaction burns a sequence value.
Consequences
- A product that numbers yearly documents ships one small driver over its settings; markets set the zone as data.
- A series counts in one calendar whoever issues the number, online or from a reserved block.
- The document-number field check of ADR 0342 still waits for a field marker in
@stackra/model.
Enforcement
packages/data/database/src/core/services/__tests__/sequence.service.test.ts(the owner’s zone wins over the call’s).packages/developer/gen/src/core/functions/build-manifest.function.ts(sequence_misplaced) and its test.packages/data/database/src/core/records/schema.record.ts(CREATE SEQUENCErefused) andcompile-migration.function.test.ts.- planned — a gen check for a document-number field without a
Sequence, once@stackra/modelhas the marker.
Supersedes and sources
Supersedes: none. Builds on 0342. Sources: STA-756; the wave 10 data handover (notes/handover/build-wave10-2026-10-25.md, “Still undecided: which time zone
governs a yearly series”); config-model section 3.