Skip to content

perf: replace UUIDv4 with UUIDv7 for ordered primary keys#511

Open
Mathew2k-hash wants to merge 1 commit into
Pi-Defi-world:devfrom
Mathew2k-hash:feat/uuidv7-id-generator
Open

perf: replace UUIDv4 with UUIDv7 for ordered primary keys#511
Mathew2k-hash wants to merge 1 commit into
Pi-Defi-world:devfrom
Mathew2k-hash:feat/uuidv7-id-generator

Conversation

@Mathew2k-hash

@Mathew2k-hash Mathew2k-hash commented Jun 23, 2026

Copy link
Copy Markdown
Contributor

perf: replace UUIDv4 with UUIDv7 for ordered primary keys

Summary

crypto.randomUUID() generates random (UUIDv4) identifiers, which scatter inserts randomly
across PostgreSQL B-tree index pages, causing fragmentation and degrading write performance
over time.

This PR introduces src/utils/idGenerator.ts — a zero-dependency UUIDv7 implementation using
Node.js built-in crypto. UUIDv7 embeds a 48-bit millisecond timestamp as the most-significant
bits, so new rows land on the tail of the index (sequential inserts), dramatically reducing
page splits and improving locality.

Changes

  • New: src/utils/idGenerator.ts — UUIDv7 generator with a 12-bit monotonic counter to guarantee
    strict ordering within the same millisecond and safe clock-overflow handling
  • Updated: 12 files across controllers, services, and jobs — all crypto.randomUUID() /
    randomUUID() runtime calls replaced with generateId(); doc comments left unchanged

Testing

  • Verified 1000 sequential IDs are unique and lexicographically sorted in insertion order
  • Build confirmed clean (pre-existing unrelated TS errors in src/config/mongodb.ts not
    introduced by this change)

closes #439

Summary by CodeRabbit

  • Refactor
    • Updated ID generation mechanism across authentication, transfers, withdrawals, compliance, KYC, bills, onramp, and webhook handlers. Correlation IDs, tokens, account references, and transaction identifiers throughout the platform now use an improved timestamp-ordered format to enhance consistency and traceability.

- Add src/utils/idGenerator.ts with UUIDv7 implementation
- UUIDv7 is timestamp-ordered, reducing B-tree index fragmentation
  in PostgreSQL compared to random UUIDv4
- Includes monotonic counter for strict ordering within same millisecond
- Replace all crypto.randomUUID() calls across controllers, services, and jobs
@drips-wave

drips-wave Bot commented Jun 23, 2026

Copy link
Copy Markdown

@Mathew2k-hash Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

@coderabbitai

coderabbitai Bot commented Jun 23, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Introduces a new generateId() utility in src/utils/idGenerator.ts that produces timestamp-ordered UUIDv7-style strings with monotonic sequencing. All existing crypto.randomUUID() call sites across 12 files—controllers, jobs, and services—are replaced with this utility.

Changes

UUIDv7 ID Generator Rollout

Layer / File(s) Summary
generateId() UUIDv7 utility
src/utils/idGenerator.ts
Adds the new exported generateId() function: module-level lastMs/seq state for monotonic ordering, BigInt timestamp splitting, UUIDv7 version/variant bit assembly, and crypto.randomBytes(8) for the random tail segments.
Auth service: token and token-family IDs
src/services/auth/authService.ts
Replaces randomUUID() with generateId() in generateSecureRefreshToken (two base64-encoded values for token bytes), issueRefreshToken (tokenFamilyId), and refreshAccessToken rotation (tokenFamilyId).
Controllers: correlation, tombstone, and document IDs
src/controllers/complianceController.ts, src/controllers/userController.ts, src/controllers/kycController.ts, src/controllers/onrampController.ts, src/controllers/webhookController.ts
Replaces crypto.randomUUID() with generateId() for tombstone suffixes in deleteAccount and deleteMe, fallback documentId in requestUploadUrl, correlationId in registerOnRampSwap, and fallback IDs in both handlePaystackWebhook and handleFlutterwaveWebhook.
Jobs and services: correlation and provider reference IDs
src/jobs/withdrawalProcessingJob.ts, src/jobs/xlmToAcbuJob.ts, src/services/bills/billsService.ts, src/services/bills/simulatedBillsPartner.ts, src/services/salary/salaryService.ts, src/services/transfer/transferService.ts
Replaces crypto.randomUUID() with generateId() for correlationId in withdrawal, XLM-to-ACBU, bill payment/reconciliation/refund, salary batch, and transfer flows; also replaces providerReference generation in SimulatedBillsPartner.payBill.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Possibly related PRs

Poem

🐇 A hop through timestamps, a twist of hex,
UUIDv7 now flexes its specs!
No more random v4 scattered wide—
Monotonic IDs march side by side.
The indexes breathe, the B-trees align,
This bunny's code now sorts just fine! 🎉

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 57.14% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely summarizes the main change: replacing UUIDv4 with UUIDv7 for ordered primary keys to improve database performance.
Description check ✅ Passed The description follows the template with a complete summary explaining the problem, solution, and changes. Scope is checked (Backend API behavior), validation steps are listed, and the issue link (#439) is provided.
Linked Issues check ✅ Passed The PR directly fulfills issue #439 by implementing a UUIDv7 generator that replaces crypto.randomUUID() across 12 files, addressing the index fragmentation problem through timestamp-based ordering.
Out of Scope Changes check ✅ Passed All changes are directly related to the stated objective of replacing UUIDv4 with UUIDv7. The 12 modified files consistently implement this single concern without introducing unrelated functionality.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
⚔️ Resolve merge conflicts
  • Resolve merge conflict in branch feat/uuidv7-id-generator

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 10

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/controllers/complianceController.ts`:
- Line 92: The tombstoneSuffix generation in the complianceController is using
the first 8 characters of generateId() which captures the time-derived prefix of
UUIDv7-style IDs, making the suffix predictable and prone to collisions during
burst deletes. Fix this by changing the substring call in the tombstoneSuffix
assignment to use the random tail bits of the ID instead of the leading
timestamp portion, such as using substring with indices that target the end of
the generated ID rather than the beginning.

In `@src/controllers/onrampController.ts`:
- Line 8: Fix the Prettier formatting violations in the onrampController.ts
file. On line 8, adjust the import statement for generateId to comply with
Prettier's formatting rules by checking line length, spacing, and proper
formatting. Additionally, on lines 127-129, fix the correlation fallback
formatting to meet ESLint/Prettier standards by reviewing the multi-line
construct formatting, indentation, and spacing. Run Prettier on the file to
automatically format these sections correctly, or manually adjust the formatting
to match your project's Prettier configuration (including proper line breaks,
indentation, and spacing conventions).

In `@src/controllers/webhookController.ts`:
- Line 17: The import statement for generateId on line 17 and the code sections
at lines 221-223 and 302-304 in webhookController.ts have Prettier formatting
violations. Run Prettier on the entire file to automatically resolve all
formatting issues across these sections. This will ensure consistent formatting
throughout the file in compliance with the project's Prettier configuration.

In `@src/jobs/withdrawalProcessingJob.ts`:
- Line 5: The import statement for generateId from '../utils/idGenerator' on
line 5 uses single quotes which does not comply with Prettier's quote style
configuration. Change the single quotes around the import path
'../utils/idGenerator' to double quotes to satisfy Prettier's formatting rules.

In `@src/jobs/xlmToAcbuJob.ts`:
- Line 12: The import statement for generateId from '../utils/idGenerator' on
line 12 violates Prettier formatting rules due to incorrect quote style.
Normalize the quotes around the module path in this import statement to match
your project's Prettier configuration, likely requiring double quotes instead of
single quotes around the module path string.

In `@src/services/auth/authService.ts`:
- Around line 892-893: The refresh-token secret generation in the code around
lines 892-893 is using generateId() which produces predictable tokens with
embedded timestamp/counter structure. Replace the
Buffer.from(generateId()).toString('base64') calls used for the refresh-token
secret with cryptographically random bytes generated from a CSPRNG (such as
crypto.randomBytes()). Keep using generateId() only for the tokenFamilyId if
present, but ensure the actual refresh-token secret portion uses properly random
cryptographic bytes instead.

In `@src/services/bills/billsService.ts`:
- Line 3: The import statement for generateId from the idGenerator utility is
using single quotes around the module path, which violates the configured
Prettier quote style rule. Change the single quotes to double quotes in the
import statement where generateId is imported from '../../utils/idGenerator' to
match the project's quote style configuration.

In `@src/services/bills/simulatedBillsPartner.ts`:
- Line 10: The import statement for generateId from utils/idGenerator on line 10
uses single quotes but does not match the project's Prettier configuration for
quote style. Change the quotes around the import path '../../utils/idGenerator'
to match the Prettier config (typically double quotes are the default). Update
the import statement to use the correct quote style consistently with the rest
of the codebase.

In `@src/utils/idGenerator.ts`:
- Around line 24-25: The timestamp fields in the UUIDv7 generation are
incorrectly ordered, breaking lexical ordering. In the timeLow and timeMid
variable assignments (lines 24-25 and also at lines 32-33), swap the bit
extraction logic so that timeLow receives the upper 32 bits of the millisecond
timestamp (ms right-shifted by 16) and timeMid receives the lower 16 bits (ms
masked with 0xffff). This ensures the first 48 bits of the UUID represent the
millisecond timestamp in proper big-endian order, which is required for UUIDv7
index-locality behavior.
- Around line 15-21: The monotonic ordering logic does not handle the case where
the current timestamp moves backward (ms < lastMs), which can occur due to time
skew or NTP adjustments. Currently, the else branch unconditionally resets
lastMs to the new (earlier) value, breaking monotonicity. Add a condition to
check if ms is less than lastMs in addition to checking if ms equals lastMs.
When the clock moves backward, either wait for the lastMs timestamp to elapse or
use lastMs as the basis for the ID and increment the sequence counter to ensure
uniqueness, rather than resetting the sequence. This ensures the ID generator
maintains strictly monotonic ordering regardless of system clock adjustments.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 6a2de120-9a74-45da-8e6d-a5943a40bdfb

📥 Commits

Reviewing files that changed from the base of the PR and between a8bb67c and 0359c42.

📒 Files selected for processing (13)
  • src/controllers/complianceController.ts
  • src/controllers/kycController.ts
  • src/controllers/onrampController.ts
  • src/controllers/userController.ts
  • src/controllers/webhookController.ts
  • src/jobs/withdrawalProcessingJob.ts
  • src/jobs/xlmToAcbuJob.ts
  • src/services/auth/authService.ts
  • src/services/bills/billsService.ts
  • src/services/bills/simulatedBillsPartner.ts
  • src/services/salary/salaryService.ts
  • src/services/transfer/transferService.ts
  • src/utils/idGenerator.ts


// 2. Tombstone the User record
const tombstoneSuffix = crypto.randomUUID().substring(0, 8);
const tombstoneSuffix = generateId().substring(0, 8);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Avoid timestamp-prefixed tombstone suffixes

Line 92 takes substring(0, 8) from generateId(). For UUIDv7-style IDs, the prefix is time-derived, so suffixes become predictable and can collide under burst deletes. Use random tail bits instead of the leading timestamp portion.

Suggested fix
-      const tombstoneSuffix = generateId().substring(0, 8);
+      const tombstoneSuffix = generateId().replace(/-/g, "").slice(-8);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const tombstoneSuffix = generateId().substring(0, 8);
const tombstoneSuffix = generateId().replace(/-/g, "").slice(-8);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/controllers/complianceController.ts` at line 92, The tombstoneSuffix
generation in the complianceController is using the first 8 characters of
generateId() which captures the time-derived prefix of UUIDv7-style IDs, making
the suffix predictable and prone to collisions during burst deletes. Fix this by
changing the substring call in the tombstoneSuffix assignment to use the random
tail bits of the ID instead of the leading timestamp portion, such as using
substring with indices that target the end of the generated ID rather than the
beginning.

import { Response, NextFunction } from "express";
import { z } from "zod";
import crypto from "crypto";
import { generateId } from '../utils/idGenerator';

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Fix Prettier violations on the new import and correlation fallback formatting.

Line 8 and Lines 127-129 are currently failing ESLint/Prettier.

Suggested patch
-import { generateId } from '../utils/idGenerator';
+import { generateId } from "../utils/idGenerator";
@@
-    const correlationId =
-      (req.headers["x-request-id"] as string | undefined) ??
-      generateId();
+    const correlationId =
+      (req.headers["x-request-id"] as string | undefined) ?? generateId();

Also applies to: 127-129

🧰 Tools
🪛 ESLint

[error] 8-8: Replace '../utils/idGenerator' with "../utils/idGenerator"

(prettier/prettier)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/controllers/onrampController.ts` at line 8, Fix the Prettier formatting
violations in the onrampController.ts file. On line 8, adjust the import
statement for generateId to comply with Prettier's formatting rules by checking
line length, spacing, and proper formatting. Additionally, on lines 127-129, fix
the correlation fallback formatting to meet ESLint/Prettier standards by
reviewing the multi-line construct formatting, indentation, and spacing. Run
Prettier on the file to automatically format these sections correctly, or
manually adjust the formatting to match your project's Prettier configuration
(including proper line breaks, indentation, and spacing conventions).

Source: Linters/SAST tools

}
import { Request, Response, NextFunction } from "express";
import crypto from "crypto";
import { generateId } from '../utils/idGenerator';

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Resolve ESLint/Prettier formatting errors in the touched webhook paths.

Line 17 and Lines 221-223/302-304 are flagged by Prettier in the current diff.

Suggested patch
-import { generateId } from '../utils/idGenerator';
+import { generateId } from "../utils/idGenerator";
@@
-    const paystackCorrelationId =
-      (req.headers["x-request-id"] as string | undefined) ??
-      generateId();
+    const paystackCorrelationId =
+      (req.headers["x-request-id"] as string | undefined) ?? generateId();
@@
-    const flwCorrelationId =
-      (req.headers["x-request-id"] as string | undefined) ??
-      generateId();
+    const flwCorrelationId =
+      (req.headers["x-request-id"] as string | undefined) ?? generateId();

Also applies to: 221-223, 302-304

🧰 Tools
🪛 ESLint

[error] 17-17: Replace '../utils/idGenerator' with "../utils/idGenerator"

(prettier/prettier)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/controllers/webhookController.ts` at line 17, The import statement for
generateId on line 17 and the code sections at lines 221-223 and 302-304 in
webhookController.ts have Prettier formatting violations. Run Prettier on the
entire file to automatically resolve all formatting issues across these
sections. This will ensure consistent formatting throughout the file in
compliance with the project's Prettier configuration.

Source: Linters/SAST tools

* disburse via fintech, update transaction status, optionally publish user notification.
*/
import { randomUUID } from "crypto";
import { generateId } from '../utils/idGenerator';

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Fix import quote style to satisfy Prettier.

Line 5 is currently flagged by ESLint/Prettier.

Suggested patch
-import { generateId } from '../utils/idGenerator';
+import { generateId } from "../utils/idGenerator";
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
import { generateId } from '../utils/idGenerator';
import { generateId } from "../utils/idGenerator";
🧰 Tools
🪛 ESLint

[error] 5-5: Replace '../utils/idGenerator' with "../utils/idGenerator"

(prettier/prettier)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/jobs/withdrawalProcessingJob.ts` at line 5, The import statement for
generateId from '../utils/idGenerator' on line 5 uses single quotes which does
not comply with Prettier's quote style configuration. Change the single quotes
around the import path '../utils/idGenerator' to double quotes to satisfy
Prettier's formatting rules.

Source: Linters/SAST tools

Comment thread src/jobs/xlmToAcbuJob.ts
import { mintFromUsdcInternal } from "../controllers/mintController";
import { fetchXlmRateUsd } from "../services/oracle/cryptoClient";
import { randomUUID } from "crypto";
import { generateId } from '../utils/idGenerator';

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Normalize import quotes to pass Prettier.

Line 12 is reported as a Prettier violation.

Suggested patch
-import { generateId } from '../utils/idGenerator';
+import { generateId } from "../utils/idGenerator";
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
import { generateId } from '../utils/idGenerator';
import { generateId } from "../utils/idGenerator";
🧰 Tools
🪛 ESLint

[error] 12-12: Replace '../utils/idGenerator' with "../utils/idGenerator"

(prettier/prettier)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/jobs/xlmToAcbuJob.ts` at line 12, The import statement for generateId
from '../utils/idGenerator' on line 12 violates Prettier formatting rules due to
incorrect quote style. Normalize the quotes around the module path in this
import statement to match your project's Prettier configuration, likely
requiring double quotes instead of single quotes around the module path string.

Source: Linters/SAST tools

Comment on lines +892 to +893
const bytes = Buffer.from(generateId()).toString('base64');
return bytes + Buffer.from(generateId()).toString('base64');

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Use CSPRNG bytes for refresh-token secrets

Line 892 and Line 893 now build bearer refresh tokens from generateId(), which embeds timestamp/counter structure. That makes tokens more predictable than necessary and leaks issuance timing. Keep generateId() for tokenFamilyId, but generate refresh-token secrets from cryptographically random bytes.

Suggested fix
 function generateSecureRefreshToken(): string {
-  const bytes = Buffer.from(generateId()).toString('base64');
-  return bytes + Buffer.from(generateId()).toString('base64');
+  return randomBytes(48).toString("base64url");
 }
🧰 Tools
🪛 ESLint

[error] 892-892: Replace 'base64' with "base64"

(prettier/prettier)


[error] 893-893: Replace 'base64' with "base64"

(prettier/prettier)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/services/auth/authService.ts` around lines 892 - 893, The refresh-token
secret generation in the code around lines 892-893 is using generateId() which
produces predictable tokens with embedded timestamp/counter structure. Replace
the Buffer.from(generateId()).toString('base64') calls used for the
refresh-token secret with cryptographically random bytes generated from a CSPRNG
(such as crypto.randomBytes()). Keep using generateId() only for the
tokenFamilyId if present, but ensure the actual refresh-token secret portion
uses properly random cryptographic bytes instead.

@@ -1,5 +1,6 @@
import { Decimal } from "@prisma/client/runtime/library";
import { prisma } from "../../config/database";
import { generateId } from '../../utils/idGenerator';

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Fix import quote style flagged by ESLint/Prettier.

Line 3 is failing the configured Prettier rule.

Suggested patch
-import { generateId } from '../../utils/idGenerator';
+import { generateId } from "../../utils/idGenerator";
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
import { generateId } from '../../utils/idGenerator';
import { generateId } from "../../utils/idGenerator";
🧰 Tools
🪛 ESLint

[error] 3-3: Replace '../../utils/idGenerator' with "../../utils/idGenerator"

(prettier/prettier)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/services/bills/billsService.ts` at line 3, The import statement for
generateId from the idGenerator utility is using single quotes around the module
path, which violates the configured Prettier quote style rule. Change the single
quotes to double quotes in the import statement where generateId is imported
from '../../utils/idGenerator' to match the project's quote style configuration.

Source: Linters/SAST tools

PartnerBillRefundRequest,
PartnerBillRefundResponse,
} from "./types";
import { generateId } from '../../utils/idGenerator';

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Adjust import quotes to match Prettier config.

Line 10 is flagged by ESLint/Prettier.

Suggested patch
-import { generateId } from '../../utils/idGenerator';
+import { generateId } from "../../utils/idGenerator";
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
import { generateId } from '../../utils/idGenerator';
import { generateId } from "../../utils/idGenerator";
🧰 Tools
🪛 ESLint

[error] 10-10: Replace '../../utils/idGenerator' with "../../utils/idGenerator"

(prettier/prettier)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/services/bills/simulatedBillsPartner.ts` at line 10, The import statement
for generateId from utils/idGenerator on line 10 uses single quotes but does not
match the project's Prettier configuration for quote style. Change the quotes
around the import path '../../utils/idGenerator' to match the Prettier config
(typically double quotes are the default). Update the import statement to use
the correct quote style consistently with the rest of the codebase.

Source: Linters/SAST tools

Comment thread src/utils/idGenerator.ts
Comment on lines +15 to +21
if (ms === lastMs) {
seq = (seq + 1) & 0xfff;
if (seq === 0) ms = ++lastMs; // counter overflow: advance clock
} else {
seq = 0;
lastMs = ms;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Monotonic ordering regresses when Date.now() moves backward.

The state machine only checks ms === lastMs. If ms < lastMs (NTP/time skew, or immediately after the overflow branch advanced lastMs), the else path resets lastMs backward and breaks monotonic ordering guarantees.

Suggested fix
 export function generateId(): string {
   let ms = BigInt(Date.now());
+  if (ms < lastMs) ms = lastMs;
+
   if (ms === lastMs) {
     seq = (seq + 1) & 0xfff;
-    if (seq === 0) ms = ++lastMs; // counter overflow: advance clock
+    if (seq === 0) {
+      ms = lastMs + 1n; // counter overflow: advance logical clock
+    }
   } else {
     seq = 0;
-    lastMs = ms;
   }
+  lastMs = ms;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/utils/idGenerator.ts` around lines 15 - 21, The monotonic ordering logic
does not handle the case where the current timestamp moves backward (ms <
lastMs), which can occur due to time skew or NTP adjustments. Currently, the
else branch unconditionally resets lastMs to the new (earlier) value, breaking
monotonicity. Add a condition to check if ms is less than lastMs in addition to
checking if ms equals lastMs. When the clock moves backward, either wait for the
lastMs timestamp to elapse or use lastMs as the basis for the ID and increment
the sequence counter to ensure uniqueness, rather than resetting the sequence.
This ensures the ID generator maintains strictly monotonic ordering regardless
of system clock adjustments.

Comment thread src/utils/idGenerator.ts
Comment on lines +24 to +25
const timeLow = Number(ms & BigInt(0xffffffff));
const timeMid = Number((ms >> BigInt(32)) & BigInt(0xffff));

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🔴 Critical | ⚡ Quick win

Timestamp fields are swapped, so this is not UUIDv7-ordered.

Line 24/25 currently maps ms as low-32 then high-16. UUIDv7 requires the first 48 bits to be the millisecond timestamp in big-endian order, so the first 32 bits must be ms >> 16 and the next 16 bits ms & 0xffff. As written, lexical ordering will wrap every ~49.7 days and break the intended index-locality behavior.

Suggested fix
-  const timeLow = Number(ms & BigInt(0xffffffff));
-  const timeMid = Number((ms >> BigInt(32)) & BigInt(0xffff));
+  const timeLow = Number((ms >> BigInt(16)) & BigInt(0xffffffff));
+  const timeMid = Number(ms & BigInt(0xffff));

Also applies to: 32-33

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/utils/idGenerator.ts` around lines 24 - 25, The timestamp fields in the
UUIDv7 generation are incorrectly ordered, breaking lexical ordering. In the
timeLow and timeMid variable assignments (lines 24-25 and also at lines 32-33),
swap the bit extraction logic so that timeLow receives the upper 32 bits of the
millisecond timestamp (ms right-shifted by 16) and timeMid receives the lower 16
bits (ms masked with 0xffff). This ensures the first 48 bits of the UUID
represent the millisecond timestamp in proper big-endian order, which is
required for UUIDv7 index-locality behavior.

@Junman140

Copy link
Copy Markdown
Member

@Mathew2k-hash fix conflict

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

crypto.randomUUID() used for IDs instead of sortable UUIDs (UUIDv7)

2 participants