Every persistable entity in the TeqBench framework extends this contract, ensuring a consistent shape for identity and audit timestamps across all @teqbench packages.
TeqBench Models
Foundational TypeScript domain-model interfaces for the TeqBench framework — a single generic TbxDomainEntityModel<TId> contract establishing identity and audit-timestamp shape for every persistable entity consumed across all @teqbench packages.
@teqbench/tbx-models defines the single foundational contract that every persistable domain entity in the TeqBench framework extends. It is intentionally small — one generic interface TbxDomainEntityModel<TId = string> with three properties (id, createdAt, updatedAt) and nothing else. The point isn't feature surface; the point is that every other @teqbench package that touches persisted data consumes this one contract, so every entity in a TeqBench-based application shares the same identity and audit-timestamp shape.
The contract is a TypeScript interface, not a class — the package ships zero runtime code. When compiled, consuming applications gain static type-checking against the contract with no bundle-size cost, no runtime dependencies, and no behavior that could drift between versions. The only thing that can change in this package is the shape of the contract itself, and that shape is intentionally conservative: the three properties are the minimum useful set for a persistable entity across any reasonable storage backend.
Why a single shared contract
Without a shared contract, every package in the framework that modeled a persistable entity would define its own ad-hoc id / createdAt / updatedAt fields — usually with subtly different types (string vs Date, optional vs required, _id vs id, millisecond timestamps vs ISO strings, etc.). Cross-package composition would require an adapter layer for each boundary. Keeping this one contract in a single foundational package means every package modeling an entity agrees on exactly the same three fields, and cross-package code can assume them without conversion.
The generic TId parameter
The identifier type is generic (TbxDomainEntityModel<TId = string>) so consumers can adapt to whatever identifier strategy their storage backend uses without forking the interface. Common choices:
string(the default) — typically a UUID v4 generated client- or server-side. Good for distributed systems where ID generation doesn't need to round-trip to the database.number— for legacy databases with auto-increment integer keys or for packages migrating from an older data model.- Branded types — e.g.
string & { readonly __brand: 'UserId' }— for compile-time separation of identifier spaces so you can't accidentally pass aUserIdwhere anOrderIdis expected.
Because TId is generic, consumers retain full type-inference on id fields throughout their domain model without runtime cost.
Audit timestamps
createdAt and updatedAt are typed as string, carrying ISO 8601 formatted datetimes. This is deliberate: ISO 8601 strings serialize transparently to JSON without the timezone-ambiguity issues of Date objects (which JSON.stringify converts to UTC ISO strings anyway, but then JSON.parse returns strings, breaking round-trips). Storing the wire representation as the canonical type avoids one layer of conversion code at every storage boundary.
The fields are not optional. Every persistable entity in TeqBench has both — set once at creation time (createdAt) and whenever the record changes (updatedAt). Entities that don't yet have these fields populated are "pre-persisted" transient models and should use a different shape (e.g. Omit<TbxDomainEntityModel, 'createdAt' | 'updatedAt'> or a distinct input-shape interface).
When to use
Extend TbxDomainEntityModel for any domain entity that your application persists and reads back by identity. Typical examples: users, orders, content records, session records, audit events.
Do not use it for:
- Transient input shapes — form state, API request bodies, client-side derived objects that never get persisted. Define those as their own interfaces; don't inherit from the entity contract just because they're in the domain.
- Value objects — an address, a monetary amount, a date range. Value objects have no identity and aren't independently persisted.
- Non-TeqBench models — if you're modeling data for an external API or library, use that library's own contracts; don't force this shape onto it.
At a glance
- Single foundational contract — One generic interface, TbxDomainEntityModel, shared by every persistable entity across all @teqbench packages.
- Generic identifier type — Parameterized TId (defaults to string) so consumers can use UUIDs, auto-increment numbers, or branded types without forking the interface.
- ISO 8601 audit timestamps — createdAt and updatedAt are ISO 8601 strings that serialize transparently to JSON without timezone ambiguity.
- Types-only, zero runtime — Compiled-away TypeScript interfaces — no JavaScript at runtime, no bundle-size cost, no dependencies.
- Read-only identity — The id property is declared readonly so consumers can't accidentally mutate identity after creation.
- Strict minimum — Exactly three required properties — intentionally conservative so the contract stays stable across releases.
- Framework-wide consistency — Every @teqbench package that models a persistable entity extends this same contract; no per-package drift.
Concepts
- Domain entity — A persistable object in the application's problem domain that is identified by a stable id and tracked by audit timestamps.
- Identifier type (TId) — The generic parameter of TbxDomainEntityModel that lets consumers choose the identifier strategy — string (default), number, branded type, etc.
- Audit timestamp — The createdAt / updatedAt pair carrying ISO 8601 datetimes that record when the entity was created and last modified.
- ISO 8601 — The international standard for date and time representation (e.g. 2026-04-12T19:30:00Z) used as the wire format for audit timestamps.
- Branded type — A nominal-typing TypeScript pattern that prevents accidental mixing of identifiers from different domains at compile time, typically by intersecting a primitive type with a unique tag.
- Persistable entity — An object the application stores and reads back by id — contrasted with transient input shapes or value objects, which should not extend this contract.
Interfaces
TbxDomainEntityModel
Base interface for all TeqBench domain models
When to use
Extend this interface for every domain entity that will be persisted. The generic parameter allows adapting the identifier type to the backing data store (e.g., string for UUIDs, number for auto-increment keys).
Example
// Default string identifier
interface User extends TbxDomainEntityModel {
email: string;
}
// Numeric identifier
interface LegacyRecord extends TbxDomainEntityModel<number> {
label: string;
}Accessibility
Not applicable — types-only package, no UI surface.