Skip to content

feat: add transactional repository methods (InsertWithTx, CheckLimitsWithTx)#73

Open
alexgarzao wants to merge 15 commits intodevelopfrom
feat/idempotency-key-support--transactional-repository-methods
Open

feat: add transactional repository methods (InsertWithTx, CheckLimitsWithTx)#73
alexgarzao wants to merge 15 commits intodevelopfrom
feat/idempotency-key-support--transactional-repository-methods

Conversation

@alexgarzao
Copy link
Collaborator

Summary

Add WithTx variants alongside existing repository methods, enabling transactional usage without breaking existing non-transactional callers. This is the foundation for atomic deduplication in the next PR.

Changes

Repository Layer

  • InsertWithTx(ctx, db, entity): Inserts transaction validation using provided pgdb.DB parameter
  • insertInternal: Extracted shared logic between Insert and InsertWithTx (DRY)
  • Nil db validation: Returns error instead of panic when db is nil

Service Layer

  • CheckLimitsWithTx(ctx, db, input): Accepts pgdb.DB for API consistency (db param reserved for future transactional repo support)
  • checkLimitsInternal: Extracted shared logic between CheckLimits and CheckLimitsWithTx (DRY)

Interfaces

  • command.TransactionValidationRepository: Added InsertWithTx
  • query.LimitChecker: Added CheckLimitsWithTx
  • Mocks regenerated for both interfaces

Code Quality

Design Decisions

  • DD-6: Inline transaction -- tx passed as pgdb.DB parameter (no TxManager)
  • Both WithTx methods are additive -- existing methods unchanged, backward compatible
  • CheckLimitsWithTx accepts db for API consistency; underlying repos will use it when they support transactional operations

Backward Compatibility

  • Existing Insert and CheckLimits methods unchanged
  • All existing tests pass without modification

…WithTx)

Add WithTx variants alongside existing methods for transactional usage:
- InsertWithTx accepts pgdb.DB parameter for atomic operations
- CheckLimitsWithTx accepts pgdb.DB for API consistency
- Extract insertInternal/checkLimitsInternal to eliminate duplication
- Add nil db validation to InsertWithTx
- Add forbidden practice rule: no task/ticket IDs in code
- Regenerate mocks for updated interfaces
@alexgarzao alexgarzao requested a review from a team as a code owner March 20, 2026 00:17
@lerian-studio
Copy link

This PR is very large (27 files, 1359 lines changed). Consider breaking it into smaller PRs for easier review.

@lerian-studio
Copy link

Consider updating CHANGELOG.md to document this change. If this change doesn't need a changelog entry, add the skip-changelog label.

@lerian-studio
Copy link

Consider updating CHANGELOG.md to document this change. If this change doesn't need a changelog entry, add the skip-changelog label.

@lerian-studio
Copy link

This PR is very large (27 files, 1360 lines changed). Consider breaking it into smaller PRs for easier review.

@coderabbitai
Copy link

coderabbitai bot commented Mar 20, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Adds transactional entry points and shared internal helpers: InsertWithTx(ctx, db, validation) on the TransactionValidation repository and CheckLimitsWithTx(ctx, db, input) on the LimitChecker service. Centralizes insert/check logic into insertInternal and checkLimitsInternal helpers, consolidating span creation and error handling and parameterizing operation names. Updates mocks and unit tests for the new transactional methods. Also updates Swagger/OpenAPI description text, removes brief comments referencing section 4.1.1, adjusts defensive copying of nested LimitUsageDetail.Scopes, and updates CI/workflow and Dockerfile metadata.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant Repo as TransactionValidationRepository
    participant DB
    participant Tracer

    Client->>Repo: InsertWithTx(ctx, db, validation)
    Repo->>Tracer: Start span "repository.transaction_validation.insert_with_tx"
    Repo->>Repo: insertInternal(ctx, db, validation, logger, span, operationName)
    Repo->>DB: ExecContext("INSERT INTO transaction_validations", args)
    DB-->>Repo: Exec result / error
    Repo->>Tracer: HandleSpanError(span, err)
    Repo-->>Client: return error | nil
Loading
sequenceDiagram
    participant Client
    participant Service as LimitCheckerService
    participant LimitRepo as LimitRepository
    participant UsageRepo as UsageCounterRepository
    participant DB
    participant Tracer

    Client->>Service: CheckLimitsWithTx(ctx, db, input)
    Service->>Tracer: Start span "service.limit_checker.check_limits_with_tx"
    Service->>Service: checkLimitsInternal(ctx, input, logger, span, operationName)
    Service->>LimitRepo: List(applicable limits)
    LimitRepo-->>Service: limits
    Service->>UsageRepo: UpsertAndIncrementAtomic(..., /* may use db */)
    UsageRepo-->>Service: updated usage / error
    Service->>Tracer: HandleSpanError(span, err)
    Service-->>Client: CheckLimitsOutput | error
Loading
🚥 Pre-merge checks | ✅ 1 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Description check ❓ Inconclusive The PR description covers key aspects: summary of changes, repository and service layer modifications, interface updates, and design decisions. However, it does not follow the required template structure with explicit checklist items completion. Consider following the repository's PR template by explicitly marking checklist items as completed (e.g., testing, documentation, coding standards, security checks) to provide full transparency on review readiness.
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main changes: adding transactional repository methods (InsertWithTx, CheckLimitsWithTx) with appropriate feature prefix.

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


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

@alexgarzao alexgarzao changed the base branch from develop to feat/idempotency-key-support--foundation--schema-and-query-and-input-validation March 20, 2026 00:23
@github-actions
Copy link

github-actions bot commented Mar 20, 2026

🔒 Security Scan Results — tracer

Trivy

Filesystem Scan

✅ No vulnerabilities or secrets found.

Docker Image Scan

✅ No vulnerabilities found.


Docker Hub Health Score Compliance

✅ Policies — 4/4 met

Policy Status
Default non-root user ✅ Passed
No fixable critical/high CVEs ✅ Passed
No high-profile vulnerabilities ✅ Passed
No AGPL v3 licenses ✅ Passed

🔍 View full scan logs

@alexgarzao alexgarzao changed the base branch from feat/idempotency-key-support--foundation--schema-and-query-and-input-validation to develop March 20, 2026 14:11
@coderabbitai
Copy link

coderabbitai bot commented Mar 20, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

gandalf-at-lerian

This comment was marked as resolved.

coderabbitai[bot]

This comment was marked as resolved.

@lerian-studio
Copy link

lerian-studio commented Mar 20, 2026

📊 Unit Test Coverage Report: tracer

Metric Value
Overall Coverage 82.8% ⚠️ BELOW THRESHOLD
Threshold 85%

Coverage by Package

Package Coverage
tracer/internal/adapters/cel 81.9%
tracer/internal/adapters/http/in/middleware 62.0%
tracer/internal/adapters/http/in 81.5%
tracer/internal/adapters/postgres/db 0.0%
tracer/internal/adapters/postgres 74.8%
tracer/internal/services/cache 95.6%
tracer/internal/services/command 81.5%
tracer/internal/services/query 80.6%
tracer/internal/services/workers 79.7%
tracer/internal/services 40.2%
tracer/internal/testhelper 0.0%
tracer/pkg/clock 50.0%
tracer/pkg/contextutil 100.0%
tracer/pkg/logging 100.0%
tracer/pkg/migration 89.0%
tracer/pkg/model 95.0%
tracer/pkg/net/http 88.3%
tracer/pkg/resilience 97.8%
tracer/pkg/sanitize 87.1%
tracer/pkg/validation 50.0%
tracer/pkg 96.6%

Generated by Go PR Analysis workflow

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
internal/adapters/postgres/transaction_validation_repository.go (1)

109-124: ⚠️ Potential issue | 🟠 Major

Reject nil validation before acquiring the connection.

Insert now reaches r.conn.GetDB() before the shared helper can reject validation == nil. If connection acquisition fails first, a caller bug is surfaced as an infrastructure error instead of the deterministic validation error, and we also do unnecessary DB work on a request that should fail fast. Split the nil-validation check into a small preflight step that runs before GetDB() and reuse it from both entrypoints.

Also applies to: 147-163

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/adapters/postgres/transaction_validation_repository.go` around lines
109 - 124, Reject nil validation before acquiring the DB connection by adding a
small preflight check and reusing it from both entrypoints: move the nil check
for *model.TransactionValidation into a helper (e.g., validateNotNilValidation
or preflightValidation) and call it at the top of Insert (before r.conn.GetDB())
and in the other public entrypoint that currently runs at lines ~147-163; keep
insertInternal unchanged (it can still assume a non-nil validation) and return a
deterministic error when validation is nil instead of proceeding to GetDB().
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@internal/adapters/postgres/transaction_validation_repository_test.go`:
- Around line 1497-1547: The test
TestTransactionValidationPostgresRepository_InsertWithTx_UsesProvidedDB should
use a real sql transaction rather than *sql.DB: add sqlMock.ExpectBegin() and
call tx, err := db.Begin() (or db.BeginTx(ctx, ...)) then pass that tx into
repo.InsertWithTx(ctx, tx, tv) instead of repo.InsertWithTx(ctx, db, tv); ensure
you still ExpectExec on the mock and commit/rollback the tx and verify
sqlMock.ExpectationsWereMet() so the test asserts compatibility with *sql.Tx
used by InsertWithTx.

---

Outside diff comments:
In `@internal/adapters/postgres/transaction_validation_repository.go`:
- Around line 109-124: Reject nil validation before acquiring the DB connection
by adding a small preflight check and reusing it from both entrypoints: move the
nil check for *model.TransactionValidation into a helper (e.g.,
validateNotNilValidation or preflightValidation) and call it at the top of
Insert (before r.conn.GetDB()) and in the other public entrypoint that currently
runs at lines ~147-163; keep insertInternal unchanged (it can still assume a
non-nil validation) and return a deterministic error when validation is nil
instead of proceeding to GetDB().

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 16357a18-b9bb-4e45-8dcf-dbdcd855cad9

📥 Commits

Reviewing files that changed from the base of the PR and between 33ef5d7 and fa47d4e.

📒 Files selected for processing (8)
  • .github/workflows/build.yml
  • .github/workflows/go-combined-analysis.yml
  • .github/workflows/gptchangelog.yml
  • .github/workflows/pr-security-scan.yml
  • .github/workflows/pr-validation.yml
  • .github/workflows/release.yml
  • internal/adapters/postgres/transaction_validation_repository.go
  • internal/adapters/postgres/transaction_validation_repository_test.go

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.github/workflows/build.yml:
- Line 10: Replace the mutable tag for the reusable workflow reference
"LerianStudio/github-actions-shared-workflows/.github/workflows/build.yml@v1.18.1"
with the immutable commit SHA "09f3e9acbe91c58bac6997b4f6f7f2584a6200c5" in both
places it appears (the current occurrences using `@v1.18.1`); update the string to
"LerianStudio/github-actions-shared-workflows/.github/workflows/build.yml@09f3e9acbe91c58bac6997b4f6f7f2584a6200c5"
so the workflow is pinned to the exact commit.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: aa391465-582a-4ffd-b9b8-863f2e3d7dae

📥 Commits

Reviewing files that changed from the base of the PR and between fa47d4e and 0c8b7bc.

📒 Files selected for processing (2)
  • .github/workflows/build.yml
  • Dockerfile

jobs:
build:
uses: LerianStudio/github-actions-shared-workflows/.github/workflows/build.yml@v1.15.0
uses: LerianStudio/github-actions-shared-workflows/.github/workflows/build.yml@v1.18.1
Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

🧩 Analysis chain

🌐 Web query:

What does GitHub Actions security guidance recommend for referencing external reusable workflows: mutable tags (e.g., @v1.18.1) or immutable commit SHAs?

💡 Result:

GitHub Actions security guidance recommends referencing external reusable workflows by an immutable full commit SHA, not by a mutable ref (branch or tag like @v1 or @v1.18.1). GitHub’s reusable-workflows documentation explicitly says {ref} can be a SHA, tag, or branch, but that “using the commit SHA is the safest option for stability and security.” [1]. GitHub also recommends SHA pinning more generally to reduce supply-chain risk from compromised/moved refs [2].

Answer: immutable commit SHAs. [1][2]


🏁 Script executed:

# Check if the file exists and read lines 1-30 to see context
if [ -f .github/workflows/build.yml ]; then
  echo "=== File exists, showing lines 1-30 ==="
  head -30 .github/workflows/build.yml | cat -n
else
  echo "File .github/workflows/build.yml not found"
fi

Repository: LerianStudio/tracer

Length of output: 1071


🌐 Web query:

GitHub LerianStudio/github-actions-shared-workflows v1.18.1 commit SHA

💡 Result:

LerianStudio/github-actions-shared-workflows v1.18.1 points to commit SHA:

09f3e9acbe91c58bac6997b4f6f7f2584a6200c5 [1]


Pin reusable workflows to immutable commit SHAs.

Lines 10 and 27 use mutable tags (@v1.18.1). GitHub security guidance recommends pinning to exact commit SHAs to reduce supply-chain risk and prevent unexpected behavior changes. For v1.18.1, use commit SHA 09f3e9acbe91c58bac6997b4f6f7f2584a6200c5.

🔒 Proposed hardening
-    uses: LerianStudio/github-actions-shared-workflows/.github/workflows/build.yml@v1.18.1
+    uses: LerianStudio/github-actions-shared-workflows/.github/workflows/build.yml@09f3e9acbe91c58bac6997b4f6f7f2584a6200c5
...
-    uses: LerianStudio/github-actions-shared-workflows/.github/workflows/gitops-update.yml@v1.18.1
+    uses: LerianStudio/github-actions-shared-workflows/.github/workflows/gitops-update.yml@09f3e9acbe91c58bac6997b4f6f7f2584a6200c5
📝 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
uses: LerianStudio/github-actions-shared-workflows/.github/workflows/build.yml@v1.18.1
uses: LerianStudio/github-actions-shared-workflows/.github/workflows/build.yml@09f3e9acbe91c58bac6997b4f6f7f2584a6200c5
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/build.yml at line 10, Replace the mutable tag for the
reusable workflow reference
"LerianStudio/github-actions-shared-workflows/.github/workflows/build.yml@v1.18.1"
with the immutable commit SHA "09f3e9acbe91c58bac6997b4f6f7f2584a6200c5" in both
places it appears (the current occurrences using `@v1.18.1`); update the string to
"LerianStudio/github-actions-shared-workflows/.github/workflows/build.yml@09f3e9acbe91c58bac6997b4f6f7f2584a6200c5"
so the workflow is pinned to the exact commit.

- Add span trade-off documentation comment in InsertWithTx nil check
- Add span error annotation for FromEntity failure in insertInternal
- Add TODO(T-003) markers for future db parameter wiring in CheckLimitsWithTx
- Add TODO(T-003) markers in limit_checker_test.go for future expectations
…methods' of github.com:LerianStudio/tracer into feat/idempotency-key-support--transactional-repository-methods
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (1)
internal/services/query/limit_checker.go (1)

80-92: ⚠️ Potential issue | 🔴 Critical

CheckLimitsWithTx still isn't transactional.

db is discarded and this method delegates into the same repository path as CheckLimits, so counter mutations can still commit even if the caller rolls back its surrounding transaction. The inline TODO documents the gap, but shipping a WithTx API before the repositories honor that handle is still unsafe. Please wire db through repository WithTx methods before exposing this entrypoint, or fail fast/remove it for now.

Also applies to: 143-164

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/services/query/limit_checker.go` around lines 80 - 92, The
CheckLimitsWithTx entrypoint is not actually transactional because it discards
the db parameter and delegates to the same repository path as CheckLimits;
either thread the provided db (pgdb.DB) through the underlying repositories
using their WithTx (or equivalent) methods so all counter mutations use the
caller's transaction, or remove/fail-fast this API until repositories accept the
transactional handle; update CheckLimitsWithTx to accept *model.CheckLimitsInput
and return *model.CheckLimitsOutput as before but call
repo.WithTx(db).<method>…</method> (use the repository names and WithTx methods
found in the same package) so that all calls that mutate counters use the
transactional repo handle instead of the non-transactional path.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@internal/services/query/limit_checker_test.go`:
- Around line 5304-5305: Replace any TODO comments that include task/ticket IDs
(e.g., "TODO(T-003)") with plain "TODO" so they comply with the new no
task/ticket IDs rule; specifically update the comment containing "TODO(T-003):
When repos support WithTx, add gomock.Eq(mockDB) expectations..." to remove
"(T-003)" and do the same for the other occurrence of "TODO(T-003)" around the
later comment (previously noted at the other location), leaving the rest of the
comment text unchanged.

---

Duplicate comments:
In `@internal/services/query/limit_checker.go`:
- Around line 80-92: The CheckLimitsWithTx entrypoint is not actually
transactional because it discards the db parameter and delegates to the same
repository path as CheckLimits; either thread the provided db (pgdb.DB) through
the underlying repositories using their WithTx (or equivalent) methods so all
counter mutations use the caller's transaction, or remove/fail-fast this API
until repositories accept the transactional handle; update CheckLimitsWithTx to
accept *model.CheckLimitsInput and return *model.CheckLimitsOutput as before but
call repo.WithTx(db).<method>…</method> (use the repository names and WithTx
methods found in the same package) so that all calls that mutate counters use
the transactional repo handle instead of the non-transactional path.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: af93c69c-5958-409d-9825-ef43563eb596

📥 Commits

Reviewing files that changed from the base of the PR and between 0c8b7bc and c915e90.

📒 Files selected for processing (3)
  • internal/adapters/postgres/transaction_validation_repository.go
  • internal/services/query/limit_checker.go
  • internal/services/query/limit_checker_test.go

Comment on lines +5304 to +5305
// TODO(T-003): When repos support WithTx, add gomock.Eq(mockDB) expectations
// to verify db parameter is forwarded correctly.
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Remove task IDs from these TODO comments.

TODO(T-003) conflicts with the new no task/ticket IDs rule introduced in this PR. Use plain TODO text here and keep the work-item reference in PR/issue metadata instead.

Also applies to: 5487-5487

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/services/query/limit_checker_test.go` around lines 5304 - 5305,
Replace any TODO comments that include task/ticket IDs (e.g., "TODO(T-003)")
with plain "TODO" so they comply with the new no task/ticket IDs rule;
specifically update the comment containing "TODO(T-003): When repos support
WithTx, add gomock.Eq(mockDB) expectations..." to remove "(T-003)" and do the
same for the other occurrence of "TODO(T-003)" around the later comment
(previously noted at the other location), leaving the rest of the comment text
unchanged.

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants