BitCode supports 6 primary key strategies configured at the model level via primary_key in model JSON. Default (no config) = UUID v4 for backward compatibility.
DB-native auto-increment integer PK. Hidden in forms.
"primary_key": { "strategy": "auto_increment" }Multiple fields as PK or unique constraint. Two modes:
With surrogate (default): UUID id as PK + composite fields as UNIQUE constraint.
"primary_key": {
"strategy": "composite",
"fields": ["order_id", "product_id"],
"surrogate": true
}Without surrogate: No id column, composite fields ARE the PK. URL uses base64-encoded JSON.
"primary_key": {
"strategy": "composite",
"fields": ["product_code", "region_code"],
"surrogate": false
}Three variants: v4 (random, default), v7 (time-ordered), format (UUID v5 from template).
"primary_key": { "strategy": "uuid", "version": "v7" }"primary_key": {
"strategy": "uuid",
"version": "format",
"format": "{data.nik}-{data.type}-{time.year}",
"namespace": "customers"
}Existing field becomes PK. Shown in create form, read-only on update.
"primary_key": {
"strategy": "natural_key",
"field": "iso_code"
}Auto-generated formatted string as PK. Hidden in forms.
"primary_key": {
"strategy": "naming_series",
"field": "code",
"format": "INV/{time.year}/{sequence(6)}",
"sequence": { "reset": "yearly", "step": 1 }
}User provides PK value. Shown in create form, read-only on update.
"primary_key": {
"strategy": "manual",
"field": "sku"
}Any field can use the format engine via auto_format:
"po_number": {
"type": "string",
"max": 50,
"auto_format": {
"format": "PO/{time.year}-{time.month}/{sequence(5)}",
"sequence": { "reset": "monthly", "step": 1 }
}
}| Token | Description | Example |
|---|---|---|
{data.<field>} |
Record field value | {data.nik} |
{time.year} |
4-digit year | 2026 |
{time.month} |
2-digit month | 04 |
{time.day} |
2-digit day | 24 |
{time.hour} |
2-digit hour | 10 |
{time.minute} |
2-digit minute | 30 |
{time.now} |
ISO datetime | 2026-04-24T10:30:00Z |
{time.date} |
Date only | 2026-04-24 |
{time.unix} |
Unix timestamp | 1745487000 |
{session.user_id} |
Current user ID | |
{session.username} |
Current username | |
{session.tenant_id} |
Current tenant ID | |
{session.group_id} |
Primary group ID | |
{session.group_code} |
Primary group code | |
{setting.<key>} |
Settings table value | |
{sequence(N)} |
Zero-padded sequence, N digits | 000001 |
{substring(src,start,len)} |
Substring | {substring(data.nik,0,3)} |
{upper(src)} |
Uppercase | {upper(data.dept)} |
{lower(src)} |
Lowercase | {lower(data.name)} |
{hash(src)} |
SHA-256 first 8 hex chars | |
{uuid4} |
Random UUID v4 | |
{uuid7} |
Time-ordered UUID v7 | |
{model.name} |
Model name | |
{model.module} |
Module name | |
{random(N)} |
N random alphanumeric chars | |
{random_fixed(len,min,max)} |
Random number, fixed length | {random_fixed(3,200,999)} |
| Mode | Behavior |
|---|---|
never |
Global counter, never resets |
minutely |
Resets every minute |
hourly |
Resets every hour |
daily |
Resets daily |
monthly |
Resets monthly |
yearly |
Resets yearly |
key |
Resets when resolved template key changes |
| File | Purpose |
|---|---|
engine/internal/compiler/parser/model.go |
PK config structs and validation |
engine/internal/infrastructure/persistence/sequence.go |
Atomic sequence engine |
engine/internal/runtime/format/engine.go |
Format template engine |
engine/internal/runtime/pkgen/generator.go |
PK strategy dispatcher |
engine/internal/infrastructure/persistence/dynamic_model.go |
Strategy-aware DDL |
engine/internal/infrastructure/persistence/repository.go |
PK-aware CRUD |
engine/internal/presentation/api/crud_handler.go |
API PK generation |
engine/internal/presentation/view/component_compiler.go |
Form field visibility |