Start here
v13.2 breaking change
Clear duplicate transaction references before you upgrade to Blnk v0.13.2.
This migration guide covers the breaking database change introduced in Blnk v0.13.2. Blnk now enforces a unique index on transactions.reference at the PostgreSQL layer. If you are upgrading from v0.13.1 or earlier and your ledger already contains transaction data, audit for duplicate references before you upgrade.
Breaking changes summary
- From: Non-unique index on
reference; uniqueness enforced only in application logic (with gaps on some queued and bulk paths). - To: Unique index
idx_transactions_reference_uniqueonblnk.transactions(reference). - Impact: The database migration fails at startup if duplicate references already exist. After upgrade, duplicate references are rejected at the database layer, not only by application checks.
What changed
- Unique reference constraint: Every transaction
referencemust be unique in the database. If two rows share the same reference, the upgrade fails until you fix them. - Queue recovery index: The same release also improves recovery of transactions stuck in
QUEUED. This does not change how you post transactions. See Queue recovery.
Migration steps
Audit duplicate references
Before upgrading, check whether your database already contains duplicate reference values:
SELECT reference, COUNT(*) AS duplicate_count
FROM blnk.transactions
WHERE reference IS NOT NULL AND reference <> ''
GROUP BY reference
HAVING COUNT(*) > 1
ORDER BY duplicate_count DESC, reference; reference | duplicate_count
-----------+---------------
ref_123 | 3
ref_abc | 2
(2 rows)If this query returns no rows, you can proceed to upgrade.
Resolve duplicates before upgrade
This query finds duplicate references, keeps the oldest row in each group unchanged, and renames every later row by appending _dup_ plus its transaction_id.
UPDATE blnk.transactions t
SET reference = t.reference || '_dup_' || t.transaction_id
FROM (
SELECT transaction_id,
ROW_NUMBER() OVER (
PARTITION BY reference
ORDER BY created_at ASC
) AS row_num
FROM blnk.transactions
WHERE reference IS NOT NULL AND reference <> ''
) ranked
WHERE t.transaction_id = ranked.transaction_id
AND ranked.row_num > 1;transaction_id | reference
-------------------+---------------------------------
txn_f482a1b3-... | ref_123
txn_c5d9e2a1-... | ref_123_dup_txn_c5d9e2a1-...
txn_a8b3c1d2-... | ref_123_dup_txn_a8b3c1d2-...
(3 rows)The earliest ref_123 row stays as-is. The two later rows get unique references so the upgrade can proceed. Re-run the audit query from step 1 until it returns no rows.
Upgrade Blnk to v0.13.2 or later
Deploy Blnk v0.13.2 or a later release. Migrations run automatically on startup and apply 1770611011.sql.
Verify the constraint
Confirm the unique index exists:
SELECT indexname, indexdef
FROM pg_indexes
WHERE schemaname = 'blnk'
AND tablename = 'transactions'
AND indexname = 'idx_transactions_reference_unique';Optionally, post a transaction with a reference that already exists in your ledger. Blnk should reject the duplicate. The index is present and duplicate references are rejected.
Technical details
- Migration file:
1770611011.sql - Index name:
idx_transactions_reference_unique - Legacy index: Before 0.13.2,
referencehad a non-unique index (idx_transactions_referencefrom the initial schema).