Skip to content

Feature/on delete edit functionality#55

Merged
AyushAdh1 merged 6 commits into
mainfrom
feature/ON-delete-edit-functionality
May 13, 2026
Merged

Feature/on delete edit functionality#55
AyushAdh1 merged 6 commits into
mainfrom
feature/ON-delete-edit-functionality

Conversation

@AyushAdh1
Copy link
Copy Markdown
Collaborator

@AyushAdh1 AyushAdh1 commented May 13, 2026

Summary by CodeRabbit

  • New Features

    • Bulk slot booking now includes user name and phone number in requests.
    • Soft-delete for fields (deactivates related rule books and membership plans).
    • Delete membership plan and delete rule book endpoints added.
    • Rule books support effective dates and historical versions for scheduling/pricing.
  • Documentation

    • Added comprehensive bulk booking API docs with examples.
    • README updated with production database reset instruction.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 13, 2026

📝 Walkthrough

Walkthrough

This PR adds rule-book versioning and history, a new FieldRuleBookHistory entity and migrations, soft-delete endpoints for fields/rule-books/memberships, refactors slot sync to resolve prices from effective rule versions, updates DTOs and docs (bulk booking payload now includes userName/phoneNumber), and wires the new entity into modules and the data source.

Changes

Soft-delete endpoints & membership cancellation

Layer / File(s) Summary
Controller routes and guards
src/fields/fields.controller.ts, src/booking/membership-plan.controller.ts
Add admin-guarded DELETE /fields/:fieldId, DELETE /fields/:fieldId/rule-books/:ruleBookId, and DELETE /membership-plans/:id handlers that forward authenticated account and UUID params to service methods.
Service behavior: delete flows
src/fields/fields.service.ts
Implements deleteField (pessimistic lock, require ≥1 remaining active field, soft-deactivate field, rule books, and set membership end dates) and deleteRuleBook (ownership check, soft-deactivate, attempt slot resync). Returns structured success/error objects.
API docs for delete operations
ApiDocs/HelloFutsal/Create Field/DeleteField/DeleteField.bru, ApiDocs/HelloFutsal/Rule Book/DeleteRuleBook/DeleteRuleBook.bru, ApiDocs/HelloFutsal/MembershipSlots/DeleteMembership/DeleteMembership.bru
Add Bruno request definitions and human-readable documentation for the new delete endpoints and requirements.

Rule-book versioning + history

Layer / File(s) Summary
History entity + migration
src/fields/entities/field-rule-book-history.entity.ts, src/migrations/1780000000004-CreateFieldRuleBookHistory.ts
Add FieldRuleBookHistory TypeORM entity and migration creating field_rule_book_history with composite unique index (ruleBookId, effectiveFromDate) and FK cascade to field_rule_books.
Schema migration for effectiveDate & history columns
src/migrations/1780000000005-AddEffectiveDateAndVersionFieldsToRuleBooks.ts
Add nullable effective_date to field_rule_books, add/backfill columns on history table, and provide down-path to remove them.
Entity and DTO changes
src/fields/entities/field-rule-book.entity.ts, src/fields/dto/create-field-rule-book.dto.ts
Add nullable effectiveDate column to FieldRuleBook and an optional effectiveDate?: string on CreateFieldRuleBookDto validated as YYYY-MM-DD.
History persistence on updates
src/fields/fields.service.ts
On create/update, set or compute effectiveDate, prevent backdating (reject earlier effective dates), and upsert prior-version rows into FieldRuleBookHistory inside transactions; convert slot-sync failures post-update into non-throwing responses with slotsUpdated: false.

Slot price resolution using effective versions

Layer / File(s) Summary
Abstract rule shape and generator changes
src/fields/cron/field-slot-generator.ts
Introduce exported RuleBookLike interface and update pricing/resolution helpers (resolveSlotPriceFromRules, resolvePriceByActionType, getRuleBookAllSlotsConfig, getRuleBookTimeRange, getRuleBookSpecificSlots) to accept RuleBookLike instead of concrete entity.
Resolve effective rule versions during sync
src/fields/cron/field-slot-sync.service.ts
Add RuleBookVersion type and resolveRuleBooksForDate helper that reads FieldRuleBookHistory up to slotDate, builds version timeline, selects the latest applicable version per ruleBookId, filters by isActive, and uses these versions for price resolution and compare logic. Core slot generation/update/retirement logic is preserved but fed with date-resolved rules.

Infrastructure wiring & data-source

Layer / File(s) Summary
Module & app wiring
src/fields/fields.module.ts, src/app.module.ts
Register FieldRuleBookHistory in TypeOrmModule.forFeature and in the application TypeORM entities list.
DataSource export and logging
src/data-source.ts
Introduce AppDataSource constant, include FieldRuleBookHistory in entities (via dynamic require), export AppDataSource as default, and add startup logging of resolved entity identifiers with a try/catch.

Bulk booking contract & docs updates

Layer / File(s) Summary
Bulk booking documentation
BULK_BOOKING_API.md
Add full spec for POST /bookings/bulk/time-range with authentication, request/response shapes, error codes, processing steps (validation, ownership check, user upsert by phone, slot query/filter by exact time windows, transactional booking, membership pricing), examples, and operational notes.
API doc payload adjustments and examples
ApiDocs/HelloFutsal/Booking/BulkBookSlots.bru, ApiDocs/HelloFutsal/Rule Book/EditRuleBook/EditTimeRange.bru, ApiDocs/HelloFutsal/Rule Book/CreateFieldRuleBook.bru, ApiDocs/HelloFutsal/environments/Dev.bru, ApiDocs/HelloFutsal/VerifyOTP/Admin OTP Verify.bru, README.md
Change BulkBookSlots example body to include userName and phoneNumber (remove startTime/endTime), update rule-book examples (effectiveDate, activeDays, value, header token placeholders), refresh example env UUIDs and tokens, remove some deprecated rule-book update templates, and add a README production reset instruction.

Sequence Diagram

sequenceDiagram
    participant Client
    participant FieldsController
    participant FieldsService
    participant FieldSlotSyncService
    participant Database

    Client->>FieldsController: PATCH /fields/:fieldId/rule-books/:ruleBookId
    FieldsController->>FieldsService: updateFieldRuleBook(account, fieldId, ruleBookId, dto)
    FieldsService->>FieldsService: validate appliedEffectiveDate >= previousEffectiveDate
    FieldsService->>Database: BEGIN TRANSACTION
    FieldsService->>Database: UPSERT FieldRuleBookHistory (previous version)
    FieldsService->>Database: UPDATE field_rule_books SET effective_date...
    FieldsService->>Database: COMMIT
    FieldsService->>FieldSlotSyncService: syncFieldDate for affected dates
    FieldSlotSyncService->>Database: SELECT histories <= slotDate for ruleBookIds
    FieldSlotSyncService->>FieldSlotSyncService: resolveRuleBooksForDate -> choose latest version per ruleBookId
    FieldSlotSyncService->>Database: UPDATE slot prices/status based on resolved versions
    alt Sync succeeds
        FieldsService-->>Client: { success: true, slotsUpdated: true }
    else Sync fails
        FieldsService-->>Client: { success: true, slotsUpdated: false, message: "..." }
    end
Loading
sequenceDiagram
    participant Admin
    participant FieldsController
    participant FieldsService
    participant Database

    Admin->>FieldsController: DELETE /fields/:fieldId
    FieldsController->>FieldsService: deleteField(account, fieldId)
    FieldsService->>Database: BEGIN TRANSACTION (pessimistic lock)
    FieldsService->>Database: COUNT active fields for owner
    alt Enough active fields remain
        FieldsService->>Database: UPDATE fields SET isActive=false WHERE id=...
        FieldsService->>Database: UPDATE field_rule_books SET isActive=false WHERE fieldId=...
        FieldsService->>Database: UPDATE membership_plans SET isActive=false, endDate=TODAY
        FieldsService->>Database: COMMIT
        FieldsService-->>Admin: { success: true, fieldId, message }
    else Not allowed (would remove last active field)
        FieldsService->>Database: ROLLBACK
        FieldsService-->>Admin: { statusCode: 400, message }
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Poem

🐰
I hop through histories, date by date,
Rule-books versioned, no twist of fate.
Soft-deletes whisper fields away,
Slots reprice by the dawn of day,
A rabbit cheers — the sync's OK!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Title check ❓ Inconclusive The title 'Feature/on delete edit functionality' is vague and does not clearly convey what the pull request accomplishes. While 'delete' and 'edit' appear in the title, the actual changes implement comprehensive soft-deletion capabilities, rule book history/versioning, and effective date management for fields, memberships, and rule books. Rename the title to clearly describe the main feature, such as 'Add field/membership/rule-book soft-deletion with rule-book history versioning' or 'Implement soft-delete operations and rule-book versioning system'.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/ON-delete-edit-functionality

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 and usage tips.

Copy link
Copy Markdown

@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: 8

Caution

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

⚠️ Outside diff range comments (1)
src/fields/fields.service.ts (1)

1017-1075: ⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

Lock and re-read the rule book inside the transaction.

Line 1017 loads state before the transaction, then Line 1051+ versions/saves it later. Concurrent updates can snapshot the same prior state and produce lost updates or incorrect history rows.

Suggested direction
-    const existingRuleBook = await this.fieldRuleBooksRepository.findOne({
-      where: { id: ruleBookId, fieldId },
-    });
+    // Keep only existence checks outside if needed; load mutable state inside TX with lock.

...
-      const savedRuleBook =
-        await this.fieldRuleBooksRepository.manager.transaction(
+      const savedRuleBook =
+        await this.fieldRuleBooksRepository.manager.transaction(
           async (manager) => {
             const ruleBookRepo = manager.getRepository(FieldRuleBook);
             const historyRepo = manager.getRepository(FieldRuleBookHistory);
+            const lockedRuleBook = await ruleBookRepo
+              .createQueryBuilder("ruleBook")
+              .setLock("pessimistic_write")
+              .where("ruleBook.id = :ruleBookId AND ruleBook.field_id = :fieldId", { ruleBookId, fieldId })
+              .getOne();
+
+            if (!lockedRuleBook) {
+              throw new NotFoundException("Rule book not found");
+            }
+
+            const previousEffectiveDate =
+              lockedRuleBook.effectiveDate ??
+              lockedRuleBook.createdAt.toISOString().split("T")[0];

             await historyRepo.upsert(
               {
-                ruleBookId: existingRuleBook.id,
+                ruleBookId: lockedRuleBook.id,
                 effectiveFromDate: previousEffectiveDate,
-                ruleName: existingRuleBook.ruleName,
+                ruleName: lockedRuleBook.ruleName,
                 ...
               },
               ["ruleBookId", "effectiveFromDate"],
             );

-            existingRuleBook.ruleName = normalizedRuleBook.ruleName;
+            lockedRuleBook.ruleName = normalizedRuleBook.ruleName;
             ...
-            return ruleBookRepo.save(existingRuleBook);
+            return ruleBookRepo.save(lockedRuleBook);
           },
         );
🤖 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/fields/fields.service.ts` around lines 1017 - 1075, You load
existingRuleBook before starting the transaction which allows concurrent updates
to cause lost updates; move the read/lock into the transaction callback: inside
the fieldRuleBooksRepository.manager.transaction callback use
manager.getRepository(FieldRuleBook) to re-fetch the rule book by id and fieldId
with a row lock (pessimistic_write/SELECT ... FOR UPDATE), then read that locked
instance to create the history entry in FieldRuleBookHistory and apply
normalizedRuleBook changes to that same instance before saving via
ruleBookRepo.save; keep existing usage of normalizeCreateFieldRuleBookInput,
appliedEffectiveDate logic, and historyRepo.upsert but base them on the re-read
locked entity instead of the pre-transaction existingRuleBook.
🤖 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 `@ApiDocs/HelloFutsal/environments/Dev.bru`:
- Line 4: The Dev.bru environment file contains a committed bearer token under
the key "token"; remove the token value and replace it with a non-secret
placeholder (e.g. TOKEN_PLACEHOLDER) in the Dev.bru file, add Dev.bru (or the
environment files pattern) to .gitignore, rotate/revoke the exposed JWT
immediately, and purge the secret from repository history using a tool like git
filter-repo or BFG to remove the leaked value from past commits.

In `@ApiDocs/HelloFutsal/Rule` Book/DeleteRuleBook/DeleteRuleBook.bru:
- Line 8: The URL uses the templated variable {{ruleBookId}} which does not
match the environment variable name rulebookId; update the URL template to use
{{rulebookId}} (and any other occurrences such as the second instance noted) so
the request uses the same variable name as the environment and will resolve
correctly.

In `@BULK_BOOKING_API.md`:
- Around line 143-149: Remove the contradictory "409 Conflict" responses that
state "User with this phone number already exists" and instead keep the single
contract that describes the upsert/reuse behavior; specifically delete the JSON
blocks under the "409 Conflict" header(s) that return statusCode 409 and that
message (the repeated blocks referenced in the comment) so the docs reflect that
existing users are reused rather than treated as an error, and ensure only the
upsert/reuse response is documented across the file.
- Around line 9-11: The fenced code block containing the endpoint "POST
/bookings/bulk/time-range" lacks a language hint; edit that fenced block and
change the opening backticks to include the language token (e.g., add "http" so
it becomes ```http) so markdownlint MD040 is satisfied and the block is properly
highlighted.

In `@README.md`:
- Around line 97-98: Add a dedicated "⚠️ DANGER: Production Database Reset"
section around the RESET_PROD_CONFIRM=RESET_PROD npm run db:reset:prod command:
move the command out of the main flow, prepend multiple explicit warnings about
irreversible data loss, list approved scenarios when it may be used and when it
must not be used, require documented backups and explicit authorization steps
(who must sign off) before running, and note that this command should ideally
live only in internal operations runbooks (or be omitted from public README)
rather than the main README.

In `@src/fields/fields.service.ts`:
- Around line 1129-1162: Move the "at least one active field" check inside the
same transaction that deactivates the field so the check and updates are atomic:
inside the existing this.fieldsRepository.manager.transaction callback, use the
transaction manager (manager) to query/count active fields for the owner (e.g.,
via manager.getRepository(Field).createQueryBuilder("f").where("f.ownerId =
:ownerId", { ownerId: account.id }).andWhere("f.isActive =
true").setLock("pessimistic_write") ) and evaluate the count there, throwing the
BadRequestException from inside the transaction if count <= 1; then proceed to
update Field, FieldRuleBook, and MembershipPlan using the same transaction
manager and include ownerId in the update predicates where appropriate to ensure
the lock/ownership is respected.
- Around line 1187-1195: deleteRuleBook currently deactivates the rule via
fieldRuleBooksRepository.update but never triggers a slot resync, leaving
upcoming slots with stale prices; after the update in deleteRuleBook (use the
existing ruleBook variable and its fieldId), call and await the slot
synchronization routine (e.g.,
this.slotService.resyncSlotsForField(ruleBook.fieldId) or the project's
equivalent method such as syncSlotsForField/resyncSlots) and handle errors (log
and/or propagate) so slots for that field are immediately recalculated before
returning the success response.

---

Outside diff comments:
In `@src/fields/fields.service.ts`:
- Around line 1017-1075: You load existingRuleBook before starting the
transaction which allows concurrent updates to cause lost updates; move the
read/lock into the transaction callback: inside the
fieldRuleBooksRepository.manager.transaction callback use
manager.getRepository(FieldRuleBook) to re-fetch the rule book by id and fieldId
with a row lock (pessimistic_write/SELECT ... FOR UPDATE), then read that locked
instance to create the history entry in FieldRuleBookHistory and apply
normalizedRuleBook changes to that same instance before saving via
ruleBookRepo.save; keep existing usage of normalizeCreateFieldRuleBookInput,
appliedEffectiveDate logic, and historyRepo.upsert but base them on the re-read
locked entity instead of the pre-transaction existingRuleBook.
🪄 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: 61e0d731-330f-49e9-bb07-038ffb2998af

📥 Commits

Reviewing files that changed from the base of the PR and between 2c42a06 and b51d8cb.

📒 Files selected for processing (26)
  • ApiDocs/HelloFutsal/Booking/BulkBookSlots.bru
  • ApiDocs/HelloFutsal/Create Field/DeleteField/DeleteField.bru
  • ApiDocs/HelloFutsal/MembershipSlots/DeleteMembership/DeleteMembership.bru
  • ApiDocs/HelloFutsal/Rule Book/CreateFieldRuleBook.bru
  • ApiDocs/HelloFutsal/Rule Book/DeleteRuleBook/DeleteRuleBook.bru
  • ApiDocs/HelloFutsal/Rule Book/EditRuleBook/EditTimeRange.bru
  • ApiDocs/HelloFutsal/Rule Book/UpdateFieldRuleBookAllSlots.bru
  • ApiDocs/HelloFutsal/Rule Book/UpdateFieldRuleBookSpecificSlots.bru
  • ApiDocs/HelloFutsal/Rule Book/UpdateFieldRuleBookTimeRange.bru
  • ApiDocs/HelloFutsal/VerifyOTP/Admin OTP Verify.bru
  • ApiDocs/HelloFutsal/environments/Dev.bru
  • BULK_BOOKING_API.md
  • README.md
  • src/app.module.ts
  • src/booking/membership-plan.controller.ts
  • src/data-source.ts
  • src/fields/cron/field-slot-generator.ts
  • src/fields/cron/field-slot-sync.service.ts
  • src/fields/dto/create-field-rule-book.dto.ts
  • src/fields/entities/field-rule-book-history.entity.ts
  • src/fields/entities/field-rule-book.entity.ts
  • src/fields/fields.controller.ts
  • src/fields/fields.module.ts
  • src/fields/fields.service.ts
  • src/migrations/1780000000004-CreateFieldRuleBookHistory.ts
  • src/migrations/1780000000005-AddEffectiveDateAndVersionFieldsToRuleBooks.ts
💤 Files with no reviewable changes (4)
  • ApiDocs/HelloFutsal/Rule Book/UpdateFieldRuleBookAllSlots.bru
  • ApiDocs/HelloFutsal/Rule Book/UpdateFieldRuleBookTimeRange.bru
  • ApiDocs/HelloFutsal/Booking/BulkBookSlots.bru
  • ApiDocs/HelloFutsal/Rule Book/UpdateFieldRuleBookSpecificSlots.bru

fieldId: 1bdfdb6b-41d8-4e39-a38c-398bdca0ba39
token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIzMDIyMWFkOS0zZjgyLTQzZDgtYjQ1OS1kZGYyMGY2YzgzOTAiLCJlbWFpbCI6bnVsbCwibW9iaWxlTnVtYmVyIjoiOTg2Nzc1NDczOCIsInJvbGUiOiJhZG1pbiIsImlhdCI6MTc3ODMwMDMyOSwiZXhwIjoxNzc4Mzg2NzI5fQ.GHeUq7DIOmimuj6eBVFtFq6HiFXf9oSQP8RS0pW1sCU
fieldId: 7e64459c-4a92-490c-bfdd-4ab660a626e9
token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIzZjljZWYwZi0zZGQ0LTQwOGMtYTI2Ni0wMDJjN2E3MjlhODUiLCJlbWFpbCI6bnVsbCwibW9iaWxlTnVtYmVyIjoiOTg2Nzc1NDczOCIsInJvbGUiOiJhZG1pbiIsImlhdCI6MTc3ODYzNzYxNywiZXhwIjoxNzc4NzI0MDE3fQ.lF51reUEi07ST1GxobnaRq_nQ9vHWKrmRwRx9yryfYU
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Remove committed bearer token from tracked environment file.

A real JWT is committed in source control. Even if expired, this is a secrets-handling breach and encourages unsafe reuse.

Suggested fix
-  token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
+  token: YOUR_TOKEN_HERE
📝 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
token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIzZjljZWYwZi0zZGQ0LTQwOGMtYTI2Ni0wMDJjN2E3MjlhODUiLCJlbWFpbCI6bnVsbCwibW9iaWxlTnVtYmVyIjoiOTg2Nzc1NDczOCIsInJvbGUiOiJhZG1pbiIsImlhdCI6MTc3ODYzNzYxNywiZXhwIjoxNzc4NzI0MDE3fQ.lF51reUEi07ST1GxobnaRq_nQ9vHWKrmRwRx9yryfYU
token: YOUR_TOKEN_HERE
🤖 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 `@ApiDocs/HelloFutsal/environments/Dev.bru` at line 4, The Dev.bru environment
file contains a committed bearer token under the key "token"; remove the token
value and replace it with a non-secret placeholder (e.g. TOKEN_PLACEHOLDER) in
the Dev.bru file, add Dev.bru (or the environment files pattern) to .gitignore,
rotate/revoke the exposed JWT immediately, and purge the secret from repository
history using a tool like git filter-repo or BFG to remove the leaked value from
past commits.

Comment thread ApiDocs/HelloFutsal/Rule Book/DeleteRuleBook/DeleteRuleBook.bru
Comment thread BULK_BOOKING_API.md
Comment thread BULK_BOOKING_API.md
Comment thread BULK_BOOKING_API.md
Comment thread README.md
Comment thread src/fields/fields.service.ts Outdated
Comment thread src/fields/fields.service.ts
Copy link
Copy Markdown

@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.

🧹 Nitpick comments (2)
src/fields/fields.service.ts (2)

1195-1208: 💤 Low value

Inconsistent slot sync error handling between updateFieldRuleBook and deleteRuleBook.

updateFieldRuleBook returns { slotsUpdated: false, message: "..." } when slot sync fails, allowing the caller to know the update succeeded but sync didn't. Here, deleteRuleBook throws the error, leaving the rule book deactivated but the caller receiving an error response.

Consider aligning the behavior: either both throw on sync failure, or both return a partial-success response.

Option: Return partial success like updateFieldRuleBook
     try {
       await this.fieldSlotSyncService.syncFieldWindow(
         ruleBook.fieldId,
         0,
         this.initialSlotWindowDays,
       );
     } catch (error) {
       this.logger.error(
         `Failed to resync slots after deleting rule book id=${ruleBookId} for fieldId=${fieldId}`,
         error instanceof Error ? error.stack : String(error),
       );

-      throw error;
+      return {
+        success: true,
+        ruleBookId,
+        message: "Rule book deleted successfully, but slot synchronization failed. Please retry slot sync.",
+        slotsUpdated: false,
+      };
     }

     return {
       success: true,
       ruleBookId,
       message: "Rule book deleted successfully",
+      slotsUpdated: true,
     };
🤖 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/fields/fields.service.ts` around lines 1195 - 1208, The deleteRuleBook
flow currently catches sync errors from fieldSlotSyncService.syncFieldWindow and
rethrows, causing callers to get an error even though the rule book was
deactivated; align its behavior with updateFieldRuleBook by returning a
partial-success response instead of throwing: inside deleteRuleBook replace the
catch that rethrows with a return object like { slotsUpdated: false, message:
"Failed to resync slots after deleting rule book", details: error instanceof
Error ? error.stack : String(error) } (or follow your existing
updateFieldRuleBook response shape), ensuring you reference the same symbols
fieldSlotSyncService.syncFieldWindow and deleteRuleBook so callers can
distinguish rule-book deactivation success from slot-sync failure.

1034-1036: 💤 Low value

Potential timezone mismatch when deriving previousEffectiveDate from createdAt.

toISOString() returns a UTC timestamp. If the database/application uses a different timezone, the extracted date could differ from the intended local date (e.g., 11 PM local on Jan 2nd becomes Jan 3rd UTC).

Consider using a timezone-aware approach or ensuring createdAt is stored/interpreted consistently with effectiveDate.

Example fix using local date extraction
     const previousEffectiveDate =
       existingRuleBook.effectiveDate ??
-      existingRuleBook.createdAt.toISOString().split("T")[0];
+      FieldSlotGenerator.formatDateToString(existingRuleBook.createdAt);

Where formatDateToString formats the Date using the same timezone convention as getCurrentDateString().

🤖 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/fields/fields.service.ts` around lines 1034 - 1036, previousEffectiveDate
is derived using existingRuleBook.createdAt.toISOString() which forces UTC and
can shift the local date; replace that extraction with a timezone-aware
local-date formatter (or the project's existing helper like
formatDateToString/getCurrentDateString) and use it when computing
previousEffectiveDate instead of toISOString(). Update the assignment for
previousEffectiveDate (the code referencing existingRuleBook.effectiveDate ??
existingRuleBook.createdAt...) to call the local-date formatter so createdAt is
interpreted in the same timezone convention as effectiveDate.
🤖 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.

Nitpick comments:
In `@src/fields/fields.service.ts`:
- Around line 1195-1208: The deleteRuleBook flow currently catches sync errors
from fieldSlotSyncService.syncFieldWindow and rethrows, causing callers to get
an error even though the rule book was deactivated; align its behavior with
updateFieldRuleBook by returning a partial-success response instead of throwing:
inside deleteRuleBook replace the catch that rethrows with a return object like
{ slotsUpdated: false, message: "Failed to resync slots after deleting rule
book", details: error instanceof Error ? error.stack : String(error) } (or
follow your existing updateFieldRuleBook response shape), ensuring you reference
the same symbols fieldSlotSyncService.syncFieldWindow and deleteRuleBook so
callers can distinguish rule-book deactivation success from slot-sync failure.
- Around line 1034-1036: previousEffectiveDate is derived using
existingRuleBook.createdAt.toISOString() which forces UTC and can shift the
local date; replace that extraction with a timezone-aware local-date formatter
(or the project's existing helper like formatDateToString/getCurrentDateString)
and use it when computing previousEffectiveDate instead of toISOString(). Update
the assignment for previousEffectiveDate (the code referencing
existingRuleBook.effectiveDate ?? existingRuleBook.createdAt...) to call the
local-date formatter so createdAt is interpreted in the same timezone convention
as effectiveDate.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: b888c0cf-2b39-4785-b9ad-b897e774cdc4

📥 Commits

Reviewing files that changed from the base of the PR and between b51d8cb and 464f6e7.

📒 Files selected for processing (3)
  • ApiDocs/HelloFutsal/VerifyOTP/Admin OTP Verify.bru
  • ApiDocs/HelloFutsal/environments/Dev.bru
  • src/fields/fields.service.ts
✅ Files skipped from review due to trivial changes (1)
  • ApiDocs/HelloFutsal/VerifyOTP/Admin OTP Verify.bru
🚧 Files skipped from review as they are similar to previous changes (1)
  • ApiDocs/HelloFutsal/environments/Dev.bru

@AyushAdh1 AyushAdh1 merged commit ae95732 into main May 13, 2026
4 checks passed
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.

1 participant