feat: pessimistic locking for offer editing
When user A opens an offer, a lock is acquired (locked_by + locked_at). User B opening the same offer sees a warning banner and the form is read-only. Lock expires after 5 minutes without heartbeat. Backend: - POST /:id/lock — acquire lock (returns 423 if locked by another) - POST /:id/heartbeat — refresh lock timestamp (every 2 min) - POST /:id/unlock — release lock - GET /:id — includes locked_by info - PUT /:id — auto-releases lock on save Frontend: - Acquires lock on page load (edit mode only) - Sends heartbeat every 2 minutes - Releases lock on page unmount (navigate away) - Shows warning banner with locker's name - All inputs read-only + action buttons hidden when locked Migration: adds locked_by (INT) and locked_at (DATETIME) to quotations. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -380,6 +380,8 @@ model quotations {
|
||||
status String @default("active") @db.VarChar(20)
|
||||
scope_title String? @db.VarChar(500)
|
||||
scope_description String? @db.Text
|
||||
locked_by Int?
|
||||
locked_at DateTime? @db.DateTime(0)
|
||||
uuid String? @db.VarChar(36)
|
||||
modified_at DateTime? @db.DateTime(0)
|
||||
sync_version Int? @default(0)
|
||||
|
||||
Reference in New Issue
Block a user