Commit graph

232 commits

Author SHA1 Message Date
Alexandre Brandizzi
ca4d4833ff feat(permissions): protect configured account owner (SH-329) 2026-09-16 18:26:20 -03:00
Alexandre Brandizzi
3358ea5058 feat(dashboard): add vendor insights (SH-349) 2026-09-16 18:10:42 -03:00
Alexandre Brandizzi
d4afcced87 feat(dashboard): add regional work order metrics (SH-348) 2026-09-16 18:03:38 -03:00
Alexandre Brandizzi
441735d39d feat(permissions): expose team member permission overrides (SH-328) 2026-09-16 18:02:02 -03:00
Alexandre Brandizzi
0194748e3b feat(dashboard): add dispatcher performance (SH-347) 2026-09-16 17:58:08 -03:00
Alexandre Brandizzi
9b39d0e5ec feat(dashboard): add dispatcher workload (SH-346) 2026-09-16 17:43:49 -03:00
Alexandre Brandizzi
a2e749c72d feat(dashboard): add core dashboard metrics (SH-343) 2026-09-16 17:28:21 -03:00
Alexandre Brandizzi
45f98e8154 Merge remote-tracking branch 'origin/dev' into feat/ab/sh-303-services-registry
# Conflicts:
#	Data.SeaHavenIndustries/Auth/ApplicationDbContext.cs
2026-09-16 17:15:38 -03:00
Alexandre Brandizzi
efd13b6f60 fix(dashboard): scope stats to authenticated accounts (SH-336) 2026-09-16 17:12:03 -03:00
Alexandre Brandizzi
06f9450485 feat(services): add global services registry 2026-09-16 17:07:59 -03:00
Alexandre Brandizzi
8515676f4d feat(vendors): add admin-assigned vendor company Area
Seed an organization-wide Area catalogue (East, Central, West, California)
with stable ids, add a nullable AreaId to VendorCompany, allow only Admins
to change it through the roster endpoints, expose areas facet metadata and
an areas[n] company-directory filter with the __unassigned__ sentinel.
2026-09-16 11:34:45 -03:00
Alexandre Brandizzi
0248aea542 fix(locations): preserve contacts when deleting sites 2026-09-15 19:03:54 -03:00
Alexandre Brandizzi
4872fe5ba1 feat(locations): manage ordered site contacts 2026-09-15 19:03:54 -03:00
Alexandre Brandizzi
1a6edd255a
feat(locations): filter sites by state (#117)
Some checks are pending
Validate and deploy / Validate deployable source bundle (push) Waiting to run
Validate and deploy / Deploy shoc-backend-dev through Terraform (push) Blocked by required conditions
Validate and deploy / Deploy shoc-backend-staging to Elastic Beanstalk (push) Blocked by required conditions
2026-09-15 16:32:30 -03:00
Alexandre Brandizzi
3a4af64a64
fix(observability): preserve backend release identity (#114) 2026-09-15 16:08:14 -03:00
Alexandre Brandizzi
67089c2135
SH-281: group vendor directory by company (#115)
* feat(vendors): group directory by company

* style(vendors): format company directory query

* fix(vendors): preserve technician list contract
2026-09-15 16:02:44 -03:00
Arthur Bassi
143d613547 test(work-orders): expect media content route 2026-09-08 11:25:26 -03:00
Arthur Bassi
9d8ae5ec24 feat(work-orders): add authorized media content GET 2026-09-08 11:23:52 -03:00
Arthur Bassi
b4f2c8b763 feat(work-orders): authorize WO media content reads 2026-09-08 11:19:41 -03:00
Arthur Bassi
a25fd0bd5d feat(work-orders): stream stored WO media safely 2026-09-08 11:09:55 -03:00
Arthur Bassi
02df093798 feat(work-orders): align completion-doc size with Extra Docs 2026-09-08 11:07:17 -03:00
Arthur Bassi
b6b8d2e58f feat(work-orders): cap media uploads at 50MB 2026-09-08 11:06:05 -03:00
Alexandre Brandizzi
6ceb274bfb
feat: add API Sentry tracing (SH-298) (#105)
Some checks failed
Validate and deploy / Validate deployable source bundle (push) Has been cancelled
Validate and deploy / Deploy shoc-backend-dev through Terraform (push) Has been cancelled
Validate and deploy / Deploy shoc-backend-staging to Elastic Beanstalk (push) Has been cancelled
* feat: add API Sentry tracing

* feat: activate Sentry deployment environments

* fix: allow Sentry-free design-time tooling

* fix: trace background jobs in Sentry

* feat(observability): identify and scrub Sentry transactions

* fix(observability): finish abandoned transactions
2026-09-04 14:11:32 -03:00
Arthur Bassi
e3a2507908 fix(users): compose full Name on user list 2026-08-31 10:22:27 -03:00
Alexandre Brandizzi
b605d5be02
fix: return vendor duplicate name conflict (#92)
Some checks failed
Validate and deploy dev / Validate deployable source bundle (push) Has been cancelled
Validate and deploy dev / Deploy shoc-backend to Elastic Beanstalk dev (push) Has been cancelled
2026-08-27 14:55:09 -03:00
Alexandre Brandizzi
31a4af7da3
fix: omit unmapped sites from work order options (#89)
Some checks are pending
Validate and deploy dev / Validate deployable source bundle (push) Waiting to run
Validate and deploy dev / Deploy shoc-backend to Elastic Beanstalk dev (push) Blocked by required conditions
2026-08-26 16:39:25 -04:00
Arthur Bassi
0f2e0dacc7 fix(locations): authorize location owner on every board update
Reject account-scoped updates of foreign or orphan locations even when accountId is omitted, matching fail-closed tenant scope.
2026-08-26 14:38:34 -03:00
Arthur Bassi
4e4bb0ca90 fix(locations): reject unparseable accountId and forward cancellation
Blank accountId stays optional; nonblank parse failures return 400. Account lookup uses ExistsActiveAsync with the request token.
2026-08-26 14:18:38 -03:00
Arthur Bassi
2718fdd294 fix(locations): gate account assignment by scope and active accounts
Reject soft-deleted accounts and stop account-scoped callers from assigning or stealing locations across tenants.
2026-08-26 14:16:59 -03:00
Arthur Bassi
2be36d4eac feat(locations): persist accountId on create and update
Allow location CRUD to stamp Locations.AccountId after account existence checks so board create can resolve tenant scope.
2026-08-26 14:03:12 -03:00
Arthur Bassi
2e56ec7678 fix(work-orders): keep location account server-owned and forward create cancellation
Stop client writes from changing Locations.AccountId, make the SH-221 migration discoverable, and thread the board-create CancellationToken through lookup and persistence.
2026-08-26 10:00:02 -03:00
Arthur Bassi
61923b2a7d feat(work-orders): stamp board create account from location
Org-wide create no longer depends on customer name. POST /workorders/board requires locationId and stamps WorkOrder.AccountId from Location.AccountId.
2026-08-26 09:12:48 -03:00
Alexandre Brandizzi
5857f8483a
fix(vendors): complete directory contact fallbacks (#86)
Some checks are pending
Validate and deploy dev / Validate deployable source bundle (push) Waiting to run
Validate and deploy dev / Deploy shoc-backend to Elastic Beanstalk dev (push) Blocked by required conditions
* fix(vendors): complete directory contact fallbacks

* fix(vendors): normalize location labels

* fix(vendors): keep company location authoritative
2026-08-25 19:33:47 -04:00
Alexandre Brandizzi
9c3da9b5e3 fix(vendors): keep location fallback atomic 2026-08-21 09:40:51 -03:00
Alexandre Brandizzi
d0a90483b3 fix(vendors): show canonical list contact data 2026-08-21 09:32:58 -03:00
Alexandre Brandizzi
518d856334 fix(vendors): enforce notes length limit 2026-08-20 18:17:48 -03:00
Alexandre Brandizzi
6fffc1b591
Merge branch 'dev' into feat/sh-254-be-confirm-deactivation 2026-08-20 10:58:23 -03:00
Alexandre Brandizzi
6c16ce7047 feat(vendors): record deactivations confirmed past open work orders
SH-44's user story is about not silently orphaning active work. The
confirmation dialog tells the operator, but nothing told the system, so
a deactivation that left work orders open was indistinguishable from one
that had none.

VendorService now takes an ILogger and writes a warning naming the
vendor, the user and the number of work orders left open whenever the
guard is cleared by confirmation. Both the update and delete paths are
covered; nothing is logged when there was nothing to leave open.
2026-08-19 13:48:30 -03:00
Alexandre Brandizzi
7a0856ddf7 feat(vendors): confirm-to-deactivate with open work orders (SH-254)
SH-44 and SH-82 both left "blocks, or requires explicit confirmation" to
be decided with the team, and the implementation took the blocking
branch. SH-254 settles it the other way: the approved design offers
"Deactivate anyway" beside the list of open work orders.

Deactivation with open work orders is now permitted, but only when the
caller says it has shown them: ConfirmOpenWorkOrders on the update DTO
and a confirmOpenWorkOrders query parameter on the delete route. Absent
the flag the existing guard still throws, so nothing deactivates by
accident and no caller loses the check by omission.

confirmOpenWorkOrders is a required parameter on DeleteVendorAsync
rather than an optional one, so every call site states its intent.
2026-08-19 13:31:16 -03:00
Alexandre Brandizzi
ec9b36ce29
Merge branch 'dev' into feat/sh-250-roster-additive-patch 2026-08-19 10:27:57 -03:00
Alexandre Brandizzi
33d0b2cebf
Merge branch 'dev' into feat/sh-250-roster-additive-patch 2026-08-18 17:46:41 -03:00
Alexandre Brandizzi
5386d6129d
Merge branch 'dev' into feature/sh-196-wo-uplifts 2026-08-18 17:46:38 -03:00
arthur.bassi
5ea5a1d702 fix(work-orders): restore NTE on auto-approved revoke and serialize cancel 2026-08-18 17:39:11 -03:00
Alexandre Brandizzi
9ef2512e14 fix(vendor-roster): conflict on colliding rename, reject no-op company update (SH-250)
Two review findings on the additive PATCH path:

- AddTechniciansAsync can rename via CompanyFields.Name and write NormalizedName
  against the unique index, but the save had no guard. A colliding rename
  surfaced as an unhandled 500 from the PATCH action instead of a stable client
  conflict. Pre-check the normalized name against other live companies and throw
  VendorRosterDuplicateNameException, with a scoped catch around the save for the
  race where a competing rename commits in between. The controller maps it to a
  409 alongside the existing concurrency conflict.
- Empty-payload validation only rejected a null CompanyFields, so an all-blank
  CompanyFields object was forwarded as a company update, bumping RowVersion and
  rewriting every technician's LastModificationTime without changing any company
  data. Blank fields now collapse to no company change, and a request with
  neither technicians nor a real company value fails validation.
2026-08-18 17:33:16 -03:00
Alexandre Brandizzi
11a355bb7a feat(vendor-roster): additive PATCH endpoint for technician adds (SH-250, SH-246)
PATCH /api/vendor-company-roster/{companyId} inserts the submitted
technicians and optionally updates company fields. Technicians absent
from the payload are never removed or deactivated, so the Add Vendor
flow can no longer soft-delete an existing roster via the full-snapshot
PUT. Stale rowVersion still 409s; unknown company 404s. POST (create)
and PUT (reconcile) behaviour is unchanged.
2026-08-18 12:14:12 -03:00
Alexandre Brandizzi
577b7add31 feat(vendors): server-owned canonical trades vocabulary for SH-249 2026-08-18 12:11:13 -03:00
arthur.bassi
b81cfbb005 feat(work-orders): WO-scoped uplift endpoints and board summary (SH-196)
Expose workorders/{id}/uplifts list/create/cancel/revoke for the SH-196 dialog, aggregate upliftSummary on board rows, and add service/controller regression tests.
2026-08-13 14:49:56 -03:00
Arthur Bassi
afcb4fde8d Merge branch 'dev' into feature/wo-board-completed-date-media 2026-08-11 15:20:17 -03:00
Arthur Bassi
bca2e0d50d test(work-orders): fix sync/webhook/recon fixtures for AccountId stamp [SH-221]
Seed resolvable Customer accounts and mock account resolution so create-path CI tests match fail-closed account scope.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-11 10:54:23 -03:00
Arthur Bassi
1edcf479ae fix(work-orders): apply account scope across create and reads [SH-221]
Stamp WorkOrder.AccountId on all create paths and filter board/list/search/detail by server-derived account claims so scoped callers cannot cross accounts.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-11 10:45:37 -03:00