Commit graph

665 commits

Author SHA1 Message Date
Alexandre Brandizzi
db8470fbf9 chore(team-members): sync with dev (SH-325) 2026-09-16 21:52:44 -03:00
Alexandre Brandizzi
a0b9fabb69 fix(team-members): preserve update semantics and validate identity results (SH-326) 2026-09-16 21:48:21 -03:00
Alexandre Brandizzi
b9c916cb22 feat(team-members): add member detail editing (SH-326) 2026-09-16 21:41:55 -03:00
Alexandre Brandizzi
8a00476d38 feat(team-members): support pending member creation (SH-325) 2026-09-16 21:41:55 -03:00
Alexandre Brandizzi
69798b3e86 feat(permissions): protect configured account owner (SH-329) 2026-09-16 21:40:22 -03:00
Alexandre Brandizzi
dca8d898cb feat(dashboard): add scoped metrics contract (SH-347) 2026-09-16 21:37:17 -03:00
Alexandre Brandizzi
738c9eaf45 feat(work-orders): add region filtering (SH-348) 2026-09-16 21:27:05 -03:00
Adam Moussa
f6bd779fe0
Merge branch 'dev' into feat/ab/sh-353-dashboard-kpis-stacked 2026-09-16 20:00:32 -04:00
Adam Moussa
e7e196caba
Merge branch 'dev' into feat/ab/sh-329-account-owner 2026-09-16 20:00:18 -04:00
Alexandre Brandizzi
9bf45d65ff
Merge branch 'dev' into feat/ab/sh-330-sites-list 2026-09-16 20:58:16 -03:00
Alexandre Brandizzi
db9a94f335
Merge pull request #132 from Sea-Haven-Industries/feat/ab/sh-328-permission-overrides
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
SH-328: expose per-person permission overrides
2026-09-16 20:52:16 -03:00
Alexandre Brandizzi
660ebac628 feat(locations): support site registry queries (SH-330) 2026-09-16 20:45:15 -03:00
Alexandre Brandizzi
21b7083160
Merge branch 'dev' into feat/ab/sh-328-permission-overrides 2026-09-16 20:44:20 -03:00
Alexandre Brandizzi
1c0865ae15
Merge pull request #136 from Sea-Haven-Industries/feat/ab/sh-350-dashboard-trend
SH-350: Add dashboard trend metrics
2026-09-16 20:42:14 -03:00
Alexandre Brandizzi
63bda30595
Merge branch 'dev' into feat/ab/sh-328-permission-overrides 2026-09-16 20:36:19 -03:00
Alexandre Brandizzi
c605ceefae
Merge branch 'dev' into feat/ab/sh-348-dashboard-region 2026-09-16 20:36:16 -03:00
Alexandre Brandizzi
0bda64efc4
Merge branch 'dev' into feat/ab/sh-350-dashboard-trend 2026-09-16 20:36:14 -03:00
Alexandre Brandizzi
452d666547
Merge pull request #142 from Sea-Haven-Industries/fix/ab/sh-374-getworkorderbyid-binding
SH-374: return the work order from GetWorkorderById?id=
2026-09-16 20:34:16 -03:00
Alexandre Brandizzi
af441894d7 fix(permissions): clean up overrides on user delete and converge concurrent override writes (SH-328)
DeleteUserWithCascadeAsync never removed UserPermissionOverrides rows, and
the FK on UserId is Restrict. Once an override was saved for a member, the
admin hard-delete (DeleteUserAsync -> DeleteUserWithCascadeAsync) failed the
foreign key inside the transaction and the controller surfaced it as a 400,
so the user was never deleted. Add an explicit ExecuteDelete on
UserPermissionOverrides before the user is removed, matching how UserRoles is
already cleared in the same method (no schema change).

SetOverrideAsync was check-then-insert on the composite key with no
DbUpdateException handling, so two concurrent PUTs for the same
(UserId, PermissionKey) let the loser violate PK_UserPermissionOverrides and
return 500. Catch the conflict, detach the pending insert, and converge by
updating the persisted row to the caller's requested state.
2026-09-16 20:27:26 -03:00
Alexandre Brandizzi
e8feed1d1b
Merge branch 'dev' into feat/ab/sh-348-dashboard-region 2026-09-16 20:26:26 -03:00
Alexandre Brandizzi
fed45f423e
Merge branch 'dev' into feat/ab/sh-350-dashboard-trend 2026-09-16 20:26:23 -03:00
Alexandre Brandizzi
93ecbbd410 test(dashboard): guard Stats wire object for KPI counts (SH-353)
The added service test asserts DashboardStatsDTO, which already carried
ScheduledTomorrow, PendingUplifts and AvetaPending, so it does not guard
the regression that was actually shipped: the DashboardController Stats
anonymous response dropping those keys and leaving the tiles empty.

Add DashboardControllerTests.GetStats_SerialisesKpiCountsOnWireObject,
which drives the controller and asserts the three keys are present on the
serialised wire object, so re-dropping any of them fails a test.

Also reword the pending-uplifts comment in DashboardServiceTests: the
Pending-only-vs-ChangesRequested exclusion is the behaviour the code
ships today, an open product call, not a settled review decision.
2026-09-16 20:25:45 -03:00
Alexandre Brandizzi
7bdcc61651 fix(work-orders): bind GetWorkorderById id from the query string (SH-374) 2026-09-16 20:15:30 -03:00
Alexandre Brandizzi
22308f21f6 fix(dashboard): resolve region zones from full state names (SH-348)
Locations store State as either a two-letter postal code or a full state
name (the location list filter expands codes to both forms via
UsStateCodes.ExpandStorageValues, and dev fixtures carry State = "indiana").
DashboardRegions.Resolve only matched the two-letter key, so every location
stored as a full name fell into Unmapped/Other and the East/Central/West/
California bars undercounted.

Normalise the stored value through a new UsStateCodes.ToCode, which accepts a
code or a full name and returns the canonical postal code, before the zone
lookup. Extend the region test with full-name storage forms and add an
invariant asserting every US state and its full-name form resolves to a
canonical bucket.
2026-09-16 20:15:20 -03:00
Alexandre Brandizzi
d366f319e9 feat(uplifts): add approval decision actions (SH-210) 2026-09-16 20:11:26 -03:00
Alexandre Brandizzi
104439c239 fix(dashboard): serialise KPI counts in Stats response (SH-353)
GetKpiCountsAsync computes ScheduledTomorrow, PendingUplifts and
AvetaPending and DashboardStatsDTO carries them, but the Stats
endpoint's anonymous wire object never serialised them, so the tiles
had nothing to read. Add scheduledTomorrow, pendingUplifts and
avetaPending to the response.

Add a DashboardServiceTests case covering GetKpiCountsAsync end to end:
it asserts all three counts and pins the pendingUplifts semantics to
Status "Pending" only, excluding "ChangesRequested" (which is back with
the vendor, not awaiting an approval decision).
2026-09-16 20:07:31 -03:00
Alexandre Brandizzi
3cb1e3e3f3 feat(uplifts): add approval queue read contract (SH-207) 2026-09-16 20:03:35 -03:00
Alexandre Brandizzi
740bcaaf7d feat(team-members): add member detail editing (SH-326) 2026-09-16 20:01:46 -03:00
Alexandre Brandizzi
5877f7817f fix(dashboard): bucket trend by calendar ScheduledDate (SH-350)
ScheduledDate is persisted as a midnight calendar value (board create writes
request.ScheduledDate.Value.Date; board patch writes the parsed .Date into a
datetime2 column with no offset). GetTrendAsync treated it as a UTC instant and
converted to America/New_York, so midnight became 19:00/20:00 the previous day
and every board-scheduled work order fell into the prior bucket: a job scheduled
today read as yesterday and overdue, and the Today bucket showed zero.

Bucket by DateOnly.FromDateTime(scheduled.Date) with no conversion, matching
DashboardMetrics and WorkOrderDerivedFields, so Trend and Stats agree on the
same rows. Rewrite the daily and yearly trend tests to assert calendar-date
classification (the removed conversion had encoded the shift into their
expectations) and add a regression test that a midnight-today work order stays
in the Today bucket and is not overdue.
2026-09-16 19:57:09 -03:00
Alexandre Brandizzi
7947e2e77d feat(dashboard): expose KPI counts (SH-353) 2026-09-16 19:23:53 -03:00
Alexandre Brandizzi
fc5c7d5ca4 feat(team-members): support pending member creation (SH-325) 2026-09-16 19:14:36 -03:00
Alexandre Brandizzi
9d7efa34a6 feat(dashboard): add trend metrics (SH-350) 2026-09-16 18:42:26 -03:00
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
33f517620b feat(work-orders): link service selections to registry 2026-09-16 18:02:57 -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
d6c3cd2e24 feat(permissions): add team member permission policy foundation (SH-327) 2026-09-16 17:48:37 -03:00
Alexandre Brandizzi
9b39d0e5ec feat(dashboard): add dispatcher workload (SH-346) 2026-09-16 17:43:49 -03:00
Alexandre Brandizzi
dec8b15278 fix(services): translate duplicate name races 2026-09-16 17:31:21 -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
d204536215
Merge pull request #121 from Sea-Haven-Industries/feat/ab/sh-278-vendor-area
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
SH-278: add admin-assigned vendor company Area
2026-09-16 17:05:57 -03:00
Alexandre Brandizzi
3047c2ba59
Merge branch 'dev' into feat/ab/sh-278-vendor-area 2026-09-16 17:00:27 -03:00
Alexandre Brandizzi
65c1ed86e1 docs(terraform): document staging token scope 2026-09-16 16:07:16 -03:00
Alexandre Brandizzi
4ae6d02d55 feat(deploy): rebuild protected staging lane 2026-09-16 15:52:02 -03:00
Alexandre Brandizzi
4b772c8db3
fix(work-orders): keep SH placeholder WO numbers and block downgrades (#123)
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
SH-320: the WO number normalizer stripped every non-digit, so a manually
entered SH placeholder (e.g. SH00001) was saved as 00000000001 on both
create and patch. Keep the SH prefix, and reject replacing a saved real
APM number with an SH placeholder.
2026-09-16 15:01:10 -03:00