Skip to content

feat(api): Add concurrent subscription update conflict resolution wit…#685

Open
Tekprecious wants to merge 3 commits into
Smartdevs17:mainfrom
Tekprecious:feat/occ-conflict-resolution
Open

feat(api): Add concurrent subscription update conflict resolution wit…#685
Tekprecious wants to merge 3 commits into
Smartdevs17:mainfrom
Tekprecious:feat/occ-conflict-resolution

Conversation

@Tekprecious

Copy link
Copy Markdown

…h OCC

feat(occ): Implement optimistic concurrency control

Closes #613

Description

This pull request introduces an Optimistic Concurrency Control (OCC) mechanism to prevent silent data loss when multiple users or automated processes perform simultaneous updates on the same resource.

Previously, the system was vulnerable to the "last-writer-wins" problem, where concurrent modifications could overwrite each other without warning. For example, a support agent updating subscription notes could have their changes silently discarded if a billing process updated the same subscription's status at the same time.

This implementation resolves the issue by adding a version field to key entities (subscriptions, invoices, plans). Each update operation must now specify the version of the data it intends to modify. If the version on the server is newer, the update is rejected with a 409 Conflict error, forcing the client to resolve the conflict before retrying.

Implementation Details

The solution is implemented across the full stack:

  1. Database (db/migrations/):

    • A new SQL migration file (003_add_occ_version_column.sql) adds an integer version column to the subscriptions, invoices, and plans tables. The column defaults to 1 for new records.
  2. Backend (backend/shared/):

    • apiResponse.ts: The shared API response has been updated with a new CONFLICT_VERSION_MISMATCH error code. The error payload now includes the current version of the resource on the server, enabling clients to fetch the latest data for retries.
    • occ/OptimisticLockService.ts: This new, reusable service is the core of the backend implementation. It provides a checkVersion helper to validate entity versions before an update.
    • Auditing: When a conflict is detected, the service now logs a field-level diff of the conflicting data for easier auditing and debugging, fulfilling the "Mutation history" requirement. It also logs any use of the ?force=true admin override parameter.
  3. Client-Side (mobile/app/services/):

    • conflictResolutionService.ts: A new client-side service introduces withConflictResolution, a higher-order function designed to wrap any data mutation function.
    • Automatic Retries: This wrapper automatically catches 409 CONFLICT_VERSION_MISMATCH errors. Upon conflict, it fetches the latest version of the entity, re-applies the user's intended changes, and retries the mutation up to 3 times with exponential backoff.
    • Manual Conflict Resolution: If all automatic retries are exhausted (e.g., due to rapid, successive conflicts), the service populates a new Zustand store (useConflictStore) with the conflicting local and remote states. This enables a UI component to subscribe to the store and present a diff to the user for manual resolution.
    • Testing: A comprehensive Jest test file has been added to verify the retry logic, backoff timing, and conflict state management of the withConflictResolution service.

How to Test

  1. Open two browser tabs and navigate to the same subscription's edit page.
  2. In Tab 1, change the subscription's notes and save. The update should succeed.
  3. In Tab 2 (which still has the old data, version N), change the subscription's status and save.
  4. Expected Behavior: The save action in Tab 2 will initially fail with a 409 Conflict error because the server is now at version N+1. The withConflictResolution service will automatically:
    • Catch the 409 error.
    • Fetch the latest subscription data (which includes the new notes from Tab 1).
    • Re-apply the status change from Tab 2 onto this newer data.
    • Retry the mutation with the correct version (N+1).
    • The final update should succeed, and the subscription will correctly reflect both the new notes and the new status.

Pull Request Checklist

Quality Gates (All must pass before merge)

  • Lint: Code passes ESLint and Prettier checks
  • Type Check: TypeScript compilation succeeds
  • Tests: All tests pass
  • Build: Project builds successfully
  • Rust Format: Smart contract formatting is correct
  • Rust Clippy: Smart contract linting passes
  • Rust Tests: All smart contract tests pass
  • Rust Build: Smart contracts compile successfully

Additional Requirements

  • New code has appropriate TypeScript types
  • No hardcoded secrets or credentials
  • New features have corresponding tests
  • Documentation updated if needed

Reviewers

  • At least 1 approval required for merge
  • All CI checks must be green

This PR will not be mergeable until all quality gates pass.

…h OCC

Implements an optimistic concurrency control (OCC) mechanism using version numbers to prevent silent data loss during concurrent updates.

- Adds a 'version' field to key entities.
- Introduces a backend OptimisticLockService for version checking.
- Returns 409 Conflict on version mismatch.
- Implements a client-side service with automatic retries and exponential backoff.
- Prepares for manual conflict resolution via a Zustand store if retries fail.

Closes Smartdevs17#613
Clears out multiple workspace errors:
- Fixes Prettier layout/syntax issues in crdt.ts and .storybook/main.js.
- Resolves import/export name collisions in the design-system barrel file.
- Corrects broken relative import paths in test files.
- Removes numerous unused variables and imports flagged by the linter.
@drips-wave

drips-wave Bot commented Jun 25, 2026

Copy link
Copy Markdown

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

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.

Add concurrent subscription update conflict resolution with OCC

2 participants