Commit graph

747 commits

Author SHA1 Message Date
Arthur Bassi
0384369305
Merge pull request #171 from Sea-Haven-Industries/feat/SH-388-uplift-evidence
Some checks are pending
Backend CI / Build and test (push) Waiting to run
Backend CI / architecture (push) Waiting to run
Backend CI / review (push) Waiting to run
Backend CI / ci-complete (push) Blocked by required conditions
fix(work-orders): accept a scanned uplift evidence file (SH-388)
2026-10-05 15:53:20 +00:00
Cursor Agent
93dda60425
fix(uplifts): serialize evidence photo count with the work-order lock
Overlapping evidence uploads could both read nine photos and both save.
The count and the insert now run under ExecuteWorkOrderMutationAsync, the
same gate the dispatcher media path uses.

Co-authored-by: Arthur Bassi <bassi-arthurr@users.noreply.github.com>
2026-10-05 15:01:59 +00:00
Cursor Agent
98bd45423d
fix(uplifts): count evidence photos and require request permission
Uplift evidence uploads now share the work-order photo limit and the
RequestUplifts check used when creating an uplift.

Co-authored-by: Arthur Bassi <bassi-arthurr@users.noreply.github.com>
2026-10-05 14:31:04 +00:00
Alexandre Brandizzi
20315f6370
Merge pull request #204 from Sea-Haven-Industries/fix/ab/past-due-cancel
Some checks failed
Backend CI / Build and test (push) Has been cancelled
Backend CI / architecture (push) Has been cancelled
Backend CI / review (push) Has been cancelled
Backend CI / ci-complete (push) Has been cancelled
fix(workorders): let Cancel through the Past Due status lock
2026-10-01 23:25:42 +00:00
Alexandre Brandizzi
ee24dde218 fix(workorders): let Cancel through the Past Due status lock
Past Due blocks lifecycle status updates until Schedule On moves (SH-262),
but it also rejected Cancel WO, which the detail panel offers on Past Due
work orders. Dispatchers had to fake a reschedule to cancel. Cancel is its
own action (SH-113), so only Canceled is exempt; every other status change
stays blocked.
2026-10-01 20:02:25 -03:00
Alexandre Brandizzi
93968dc2fb
Merge pull request #203 from Sea-Haven-Industries/fix/ab/sh-412-addon-weekonly-tests
Some checks are pending
Backend CI / Build and test (push) Waiting to run
Backend CI / architecture (push) Waiting to run
Backend CI / review (push) Waiting to run
Backend CI / ci-complete (push) Blocked by required conditions
SH-412: keep Add-On stable on week-only toggles and date-less edits
2026-10-01 22:12:55 +00:00
Alexandre Brandizzi
7a14b883c3 fix: keep add-on hint when a week-only toggle leaves the schedule unmoved
Skip the add-on recalculation when neither the scheduled date nor the
target week changed, so toggling week-only on an unscheduled work order
no longer clears the create-time add-on hint.
2026-10-01 18:57:25 -03:00
Alexandre Brandizzi
efe4f5f0b9 test: pin add-on across week-only toggles and date-less edits
Keep the add-on recalculation on the week-only toggle so a future schedule
side effect cannot leave a stale tag, and cover that a toggle and an edit
without Schedule On leave Add-On unchanged.
2026-10-01 16:22:44 -03:00
Alexandre Brandizzi
2c918b0f6a
Merge pull request #202 from Sea-Haven-Industries/fix/ab/sh-412-addon-reschedule-time
Some checks are pending
Backend CI / Build and test (push) Waiting to run
Backend CI / architecture (push) Waiting to run
Backend CI / review (push) Waiting to run
Backend CI / ci-complete (push) Blocked by required conditions
SH-412: recalculate Add-On at reschedule time
2026-10-01 19:18:13 +00:00
Alexandre Brandizzi
b9f9725c73 fix: recalculate add-on at reschedule time, not creation time
A reschedule moves the work order into its new week at the moment of the
reschedule, so Add-On now compares that moment with the new week's cutoff,
matching the prototype. Moves within the same week keep the current value.
Previously an older work order moved into a week already past its cutoff
stayed off because it was created before that cutoff (SH-412).
2026-10-01 16:10:19 -03:00
Cursor Agent
1daac954a3
fix(uplifts): return stored evidence after a concurrent create
Map the saved request from the evidence-file lookup, and teach the shared-dispatch
conflict test to return that lookup so a winning insert still produces a response.

Co-authored-by: Arthur Bassi <bassi-arthurr@users.noreply.github.com>
2026-10-01 14:58:51 +00:00
Cursor Agent
b11b66538a
fix(uplifts): resolve evidence without a primary dispatch
Upload and status use the same dispatch create already selects, so a work
order with no primary can still attach evidence. Status no longer rejects a
terminal work order or dispatch, and create, cancel, and revoke return the
stored evidence file name and attachments.

Co-authored-by: Arthur Bassi <bassi-arthurr@users.noreply.github.com>
2026-10-01 14:55:07 +00:00
Alexandre Brandizzi
c655f753b2
Merge pull request #201 from Sea-Haven-Industries/fix/ab/sh-412-addon-reschedule
Some checks are pending
Backend CI / Build and test (push) Waiting to run
Backend CI / architecture (push) Waiting to run
Backend CI / review (push) Waiting to run
Backend CI / ci-complete (push) Blocked by required conditions
fix: recalculate Add-On on work order reschedule
2026-10-01 03:26:16 +00:00
Alexandre Brandizzi
c02749a4ea fix: run work order edit reschedule under the mutation lock
UpdateWorkOrderAsync loaded the work order, applied the shared schedule
side effects (RescheduleCount, OriginalDate/OriginalWeek, lifecycle,
IsAddOn) and saved with no gate, transaction or row lock, so a
concurrent reschedule could interleave with the read-modify-write.

The read, the mutation, the save and the audit entry now run through
IWorkOrderDataService.ExecuteWorkOrderMutationAsync, which uses the
shared WorkOrderMutationLock: the per-work-order in-process gate, a
transaction, and an UPDLOCK on the work order row on SQL Server. A
reschedule committed by another holder of the lock is read before the
edit applies its own date and increments RescheduleCount.

Adds a regression test that holds the gate, commits a reschedule, and
asserts the edit waits and then builds on the committed schedule.
2026-10-01 00:19:37 -03:00
Alexandre Brandizzi
24436c9864 fix: apply shared schedule side effects on work order edit
Route edit-path ScheduledDate changes through WorkOrderBoardFieldMutations.ApplyScheduledDate so OriginalDate/OriginalWeek, RescheduleCount and lifecycle promotion match the board PATCH path, and audit those changes.
2026-10-01 00:10:43 -03:00
Alexandre Brandizzi
ac5550365f fix: recalculate add-on on work order reschedule 2026-09-30 23:58:20 -03:00
Alexandre Brandizzi
d03c88d48f
Merge pull request #200 from Sea-Haven-Industries/research/ab/sh413-service-contract-thr_9fpik7tdmw
Some checks are pending
Backend CI / Build and test (push) Waiting to run
Backend CI / architecture (push) Waiting to run
Backend CI / review (push) Waiting to run
Backend CI / ci-complete (push) Blocked by required conditions
SH-413: preserve service history and filter registry names
2026-09-30 23:36:58 +00:00
Alexandre Brandizzi
969b972581 fix(workorders): search registry service labels 2026-09-30 20:19:41 -03:00
Alexandre Brandizzi
0cd0d3b066 fix(workorders): match registry service filters exactly 2026-09-30 17:08:17 -03:00
Alexandre Brandizzi
0894b20e59 fix(workorders): preserve completed service snapshots 2026-09-30 17:04:46 -03:00
Alexandre Brandizzi
aede3148d1 fix(workorders): filter inactive services by current name 2026-09-30 16:47:12 -03:00
Alexandre Brandizzi
c2e29abb5d fix(workorders): use live registry names in service filters 2026-09-30 16:45:05 -03:00
Alexandre Brandizzi
5a5472ed43
Merge pull request #199 from Sea-Haven-Industries/fix/ab/sh411-technician-assignment-backend-thr_9fpik7tdmw
Some checks failed
Backend CI / Build and test (push) Has been cancelled
Backend CI / architecture (push) Has been cancelled
Backend CI / review (push) Has been cancelled
Backend CI / ci-complete (push) Has been cancelled
Persist explicit work-order technician assignment
2026-09-29 21:58:16 +00:00
Alexandre Brandizzi
2de65539a1 test(workorders): cover technician-name search for cleared assignment
WorkOrderBoardSearchFilter now skips the vendor ContactName for work
orders whose TechnicianAssigned is explicitly false. Exercise the
predicate through SQLite so relational null semantics are covered:
legacy null and true rows still match a technician-name search, the
explicitly cleared row does not, and the vendor company name still
matches all three.
2026-09-29 18:45:05 -03:00
Alexandre Brandizzi
35adef5808 fix(workorders): persist explicit technician assignment 2026-09-29 17:58:52 -03:00
Arthur Bassi
2f4b783615 fix(uplifts): open evidence by work-order access and keep every file
Auto-approved evidence was hidden because download checked the approval tier. Viewers of the work order can open it, and a request can store more than one scanned document.
2026-09-28 16:24:26 -03:00
Arthur Bassi
31dd2d5dcd merge(main): keep uplift evidence on the current work-order routes
The route contract keeps the poc endpoint from main and the uplift evidence routes from this branch. Create still passes the scanned evidence document through the locked mutation.
2026-09-28 15:56:45 -03:00
Alexandre Brandizzi
d3b6ba01c7
Merge pull request #193 from Sea-Haven-Industries/fix/ab/sh-403-reset-hardening-2
Some checks failed
Backend CI / Build and test (push) Has been cancelled
Backend CI / architecture (push) Has been cancelled
Backend CI / review (push) Has been cancelled
Backend CI / ci-complete (push) Has been cancelled
fix(auth): cap reset abuse per account, key reset-code hashes, send reset email off the request path
2026-09-25 23:11:26 +00:00
Alexandre Brandizzi
74d5aa17eb fix(auth): trace a reset email the provider rejects as an error
A send that the mail provider did not accept finished its background
transaction as ok, so rejected reset emails looked delivered in tracing.
It now finishes as an error with a fixed message that names no recipient.
2026-09-25 20:01:58 -03:00
Alexandre Brandizzi
1077d489a8
Merge pull request #197 from Sea-Haven-Industries/fix/ab/sh-407-cancel-wo-cancels-uplift
Cancelling a work order cancels its pending uplift
2026-09-25 23:01:24 +00:00
Alexandre Brandizzi
e941e055b7 Merge remote-tracking branch 'origin/main' into fix/ab/sh-407-cancel-wo-cancels-uplift 2026-09-25 19:49:50 -03:00
Alexandre Brandizzi
c985e9423d Merge remote-tracking branch 'origin/main' into fix/ab/sh-403-reset-hardening-2
# Conflicts:
#	Api.SeaHavenIndustries.Tests/AuthenticationServiceTests.cs
#	Api.SeaHavenIndustries.Tests/PasswordPolicyTests.cs
#	SeaHaven.Services/Implementation/AuthenticationService.cs
2026-09-25 19:49:24 -03:00
Alexandre Brandizzi
de0e767930 fix(auth): refuse a reset email when the queue is full instead of dropping it
The channel used DropWrite, under which TryWrite reports success and
discards the email, so a full queue still counted the request and never
sent the code. Wait makes TryWrite return false when the queue is full,
without blocking, so the request is released and the user can ask again.
2026-09-25 19:38:53 -03:00
Alexandre Brandizzi
63465cc083
Merge pull request #198 from Sea-Haven-Industries/fix/ab/sh-409-invalidate-sessions-on-reset
End earlier sign-in sessions after a password reset, password change, deactivation or deletion
2026-09-25 22:38:44 +00:00
Alexandre Brandizzi
a32471d4c0 Serialize sync cancels and vendor uplift requests on the work order lock
The legacy ingest batch holds the per-work-order lock, taken in id order,
for every work order it may cancel until the batch commits. A vendor
uplift request now runs under the same lock. Uplift creation on both
routes refuses a work order cancelled by either lifecycle or status text,
so a request can neither slip past a cancel nor land after one.
2026-09-25 19:37:08 -03:00
Alexandre Brandizzi
0298fc75bd Merge remote-tracking branch 'origin/main' into fix/ab/sh-403-reset-hardening-2 2026-09-25 19:27:01 -03:00
Alexandre Brandizzi
498f49a2d8 fix(auth): end earlier sessions when a user's role or account changes
A token carries the user's roles and account, so a demoted admin kept admin
claims until the token expired. The team member update and the admin user
edit now rotate the security stamp and evict the cached value when the role,
account or user name changes. Permission overrides are read per request and
are not in the token.
2026-09-25 19:26:25 -03:00
Alexandre Brandizzi
987ec455f2 Merge remote-tracking branch 'origin/main' into fix/ab/sh-409-invalidate-sessions-on-reset
# Conflicts:
#	Api.SeaHavenIndustries.Tests/AuthenticationServiceTests.cs
#	Api.SeaHavenIndustries.Tests/PasswordPolicyTests.cs
#	SeaHaven.Services/Implementation/AuthenticationService.cs
2026-09-25 19:22:33 -03:00
Alexandre Brandizzi
de8e283ee5
Merge pull request #192 from Sea-Haven-Industries/fix/ab/sh-403-reset-code-hardening
Some checks are pending
Backend CI / Build and test (push) Waiting to run
Backend CI / architecture (push) Waiting to run
Backend CI / review (push) Waiting to run
Backend CI / ci-complete (push) Blocked by required conditions
fix(auth): stop reset-code guessing and email enumeration in Forgot Password
2026-09-25 22:16:01 +00:00
Alexandre Brandizzi
410bf1b4ca
Merge pull request #195 from Sea-Haven-Industries/fix/ab/sh-408-has-uplift-live-status
fix(work-orders): count only live uplifts for Has uplift and the Uplift column
2026-09-25 22:15:57 +00:00
Alexandre Brandizzi
c8e4b8f3d5
Merge pull request #196 from Sea-Haven-Industries/fix/ab/sh-406-no-revoke-auto-approved
fix(uplifts): refuse admin revoke of an auto-approved uplift
2026-09-25 22:15:54 +00:00
Alexandre Brandizzi
77dc3d85c3 Serialize a CRM cancel with uplift creation on the work order lock
The per-work-order gate moves into a shared data-layer helper. A CRM
mutation that cancels an existing work order now runs under it, so a
create in flight either commits first and is cancelled, or sees the
cancelled work order.
2026-09-25 19:15:38 -03:00
Alexandre Brandizzi
cc46950254 test(auth): format the password change request 2026-09-25 19:10:46 -03:00
Alexandre Brandizzi
b7be07411e fix(auth): end earlier sessions when a password or account status changes
Tokens now carry a keyed hash of the account's security stamp, and every
authenticated request compares it with the stored stamp (cached for 60 s,
evicted in-process on change). A password reset or change, a deactivation
and a deletion all rotate or remove the stamp, so tokens issued before them
get 401. Tokens without the claim get 401 too.
2026-09-25 19:08:33 -03:00
Alexandre Brandizzi
306ab159cc Cancel pending uplifts when the legacy ingest cancels a work order
The ingest writes only the status text, so the shared helper gains a
status-text form of the same rule and the ingest stages the same
sync-attributed cancellation in its batch save.
2026-09-25 19:01:37 -03:00
Alexandre Brandizzi
e993e1b5fc refactor(auth): compose bearer authentication through one registration 2026-09-25 18:54:10 -03:00
Alexandre Brandizzi
99499c3281 Cancel pending uplifts when the CRM cancels a work order
The webhook and reconciliation saves now stage the same pending-uplift
cancellation, with its own sync audit row, as the board cancel. The rule
and the write live in one data-layer helper so the paths cannot drift.
2026-09-25 18:48:44 -03:00
Alexandre Brandizzi
9bad363930 fix(work-orders): cancelling from the board cancels the pending uplift
The board and slide-over cancel a work order through the lifecycle status
patch, which set Canceled without touching uplifts, so a pending uplift
stayed in the approval queue. A patch to Canceled now withdraws pending
uplifts in the same save, each with its own uplift_cancel audit entry, and
runs under the per-work-order gate uplift create uses.
2026-09-25 18:37:56 -03:00
Alexandre Brandizzi
ca9322fa60 fix(auth): queue the reset email only after its code is stored 2026-09-25 18:29:33 -03:00
Alexandre Brandizzi
2f23f6fadc test(team-members): register reset email delivery in the invite test host 2026-09-25 18:10:10 -03:00