Commit graph

53 commits

Author SHA1 Message Date
renovate[bot]
caaa917db4
chore(deps): update dependency awssdk.extensions.netcore.setup to 4.0.101.1 2026-08-31 04:42:44 +00:00
renovate[bot]
9ac50567f2
chore(deps): update dependency awssdk.dynamodbv2 to v4 (#335) 2026-08-25 17:07:19 +00:00
renovate[bot]
2a21e63bbf
chore(deps): update dependency swashbuckle.aspnetcore to v10 (#352) 2026-08-25 16:55:45 +00:00
renovate[bot]
1eed50c245
chore(deps): update dependency dotnet-sdk to v10 (#342) 2026-08-25 00:49:29 +00:00
renovate[bot]
73e27e3c54
chore(deps): update dependency coverlet.collector to v10 (#341) 2026-08-25 00:25:16 +00:00
renovate[bot]
6747d05738
chore(deps): update dependency fluentvalidation to v12 (#344) 2026-08-24 23:59:41 +00:00
renovate[bot]
6b89f4d502
chore(deps): update dependency fluentassertions to v8 (#343) 2026-08-24 23:47:11 +00:00
renovate[bot]
8847cb3ee1
chore(deps): update dependency dotnet-sdk to v8.0.424 (#331) 2026-08-24 22:19:34 +00:00
renovate[bot]
d7e895ab1d
chore(deps): update dependency amazon.lambda.aspnetcoreserver.hosting to 2.2.1 (#330) 2026-08-24 22:10:46 +00:00
Adam Moussa
9e579f84e2
fix(web,api): pin nanoid and sanitize auth logs (SEC-29) (#312)
* fix: bump nanoid to 3.3.16 and postcss to 8.5.26

Bump nanoid from 3.3.16 to 3.3.18 in web/
Bump postcss from 8.5.25 to 8.5.26 in web/

Closes [Dependabot 47] (https://github.com/Sea-Haven-Industries/proposal-system/security/dependabot/47)

* fix(api): sanitize request path in internal API key logs (SEC-29)

Strip CR/LF from Request.Path before logging invalid-key and disallowed-path warnings so CodeQL alerts 4 and 5 close without changing 401/403 behavior.

* fix(api): log user id instead of email on cognito role sync (SEC-29)

Keep AuthResponse.Email unchanged so CodeQL alert 1 closes without altering the callback payload.

* fix(api): use sanitized path on both internal key logs (SEC-29)

The 401 branch referenced an out-of-scope identifier and the 403 branch skipped SanitizeForLog. Cover newline-in-path logs and Cognito role-sync user-id logging with tests.
2026-08-20 12:38:29 -04:00
dependabot[bot]
aa6dfe6e84
chore(deps): bump xunit.runner.visualstudio from 3.1.5 to 4.0.0 (#308)
---
updated-dependencies:
- dependency-name: xunit.runner.visualstudio
  dependency-version: 4.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-08-17 23:10:09 +00:00
dependabot[bot]
1e740d3204
chore(deps): misc version bumps (#306)
Bumps Microsoft.AspNetCore.Authentication.JwtBearer from 8.0.29 to 8.0.30
Bumps Microsoft.EntityFrameworkCore from 8.0.29 to 8.0.30
Bumps Microsoft.EntityFrameworkCore.Design from 8.0.29 to 8.0.30
Bumps Microsoft.EntityFrameworkCore.InMemory from 8.0.29 to 8.0.30
Bumps Microsoft.EntityFrameworkCore.Sqlite from 8.0.29 to 8.0.30
Bumps Microsoft.Extensions.Diagnostics.HealthChecks.EntityFrameworkCore from 8.0.29 to 8.0.30
Bumps Microsoft.NET.Test.Sdk from 18.8.1 to 18.9.0
Bumps NSubstitute from 6.0.0 to 6.2.0

---
updated-dependencies:
- dependency-name: Microsoft.AspNetCore.Authentication.JwtBearer
  dependency-version: 8.0.30
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: api
- dependency-name: Microsoft.EntityFrameworkCore
  dependency-version: 8.0.30
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: api
- dependency-name: Microsoft.EntityFrameworkCore.Design
  dependency-version: 8.0.30
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: api
- dependency-name: Microsoft.EntityFrameworkCore.InMemory
  dependency-version: 8.0.30
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: api
- dependency-name: Microsoft.EntityFrameworkCore.Sqlite
  dependency-version: 8.0.30
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: api
- dependency-name: Microsoft.Extensions.Diagnostics.HealthChecks.EntityFrameworkCore
  dependency-version: 8.0.30
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: api
- dependency-name: Microsoft.NET.Test.Sdk
  dependency-version: 18.9.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: api
- dependency-name: NSubstitute
  dependency-version: 6.2.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: api
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-08-17 22:48:15 +00:00
Adam Moussa
0ef46251ef
build(deps): batch six dependabot updates across web, lambdas, and api (#272)
* build(deps): bump react-router-dom in /web in the web group

Bumps the web group in /web with 1 update: [react-router-dom](https://github.com/remix-run/react-router/tree/HEAD/packages/react-router-dom).


Updates `react-router-dom` from 7.18.1 to 7.18.2
- [Release notes](https://github.com/remix-run/react-router/releases)
- [Changelog](https://github.com/remix-run/react-router/blob/react-router-dom@7.18.2/packages/react-router-dom/CHANGELOG.md)
- [Commits](https://github.com/remix-run/react-router/commits/react-router-dom@7.18.2/packages/react-router-dom)

---
updated-dependencies:
- dependency-name: react-router-dom
  dependency-version: 7.18.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: web
...

Signed-off-by: dependabot[bot] <support@github.com>

* build(deps): update boto3 requirement in /lambdas/pdf-generate

Updates the requirements on [boto3](https://github.com/boto/boto3) to permit the latest version.
- [Release notes](https://github.com/boto/boto3/releases)
- [Commits](https://github.com/boto/boto3/compare/1.43.56...1.43.58)

---
updated-dependencies:
- dependency-name: boto3
  dependency-version: 1.43.58
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>

* build(deps-dev): bump jsdom from 29.1.1 to 30.0.1 in /web

Bumps [jsdom](https://github.com/jsdom/jsdom) from 29.1.1 to 30.0.1.
- [Release notes](https://github.com/jsdom/jsdom/releases)
- [Commits](https://github.com/jsdom/jsdom/compare/v29.1.1...v30.0.1)

---
updated-dependencies:
- dependency-name: jsdom
  dependency-version: 30.0.1
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

* build(deps): update boto3 requirement in /lambdas/pdf-extract

Updates the requirements on [boto3](https://github.com/boto/boto3) to permit the latest version.
- [Release notes](https://github.com/boto/boto3/releases)
- [Commits](https://github.com/boto/boto3/compare/1.43.56...1.43.58)

---
updated-dependencies:
- dependency-name: boto3
  dependency-version: 1.43.58
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>

* build(deps): update boto3 requirement in /lambdas/aurora-pgvector-init

Updates the requirements on [boto3](https://github.com/boto/boto3) to permit the latest version.
- [Release notes](https://github.com/boto/boto3/releases)
- [Commits](https://github.com/boto/boto3/compare/1.43.56...1.43.58)

---
updated-dependencies:
- dependency-name: boto3
  dependency-version: 1.43.58
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>

* Bump Amazon.Lambda.AspNetCoreServer.Hosting from 1.10.0 to 2.2.0

---
updated-dependencies:
- dependency-name: Amazon.Lambda.AspNetCoreServer.Hosting
  dependency-version: 2.2.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-08-03 12:59:09 -04:00
Adam Moussa
d011b66467
build(deps): batch Dependabot updates (#232-#240, #242) (#243)
* build(deps): bump the infra group in /infra with 3 updates

Bumps the infra group in /infra with 3 updates: [constructs](https://github.com/aws/constructs), [aws-cdk](https://github.com/aws/aws-cdk-cli/tree/HEAD/packages/aws-cdk) and [tsx](https://github.com/privatenumber/tsx).


Updates `constructs` from 10.6.0 to 10.7.0
- [Release notes](https://github.com/aws/constructs/releases)
- [Commits](https://github.com/aws/constructs/compare/v10.6.0...v10.7.0)

Updates `aws-cdk` from 2.1130.0 to 2.1132.0
- [Release notes](https://github.com/aws/aws-cdk-cli/releases)
- [Commits](https://github.com/aws/aws-cdk-cli/commits/aws-cdk@v2.1132.0/packages/aws-cdk)

Updates `tsx` from 4.23.0 to 4.23.1
- [Release notes](https://github.com/privatenumber/tsx/releases)
- [Changelog](https://github.com/privatenumber/tsx/blob/master/release.config.cjs)
- [Commits](https://github.com/privatenumber/tsx/compare/v4.23.0...v4.23.1)

---
updated-dependencies:
- dependency-name: constructs
  dependency-version: 10.7.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: infra
- dependency-name: aws-cdk
  dependency-version: 2.1132.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: infra
- dependency-name: tsx
  dependency-version: 4.23.1
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: infra
...

Signed-off-by: dependabot[bot] <support@github.com>

* build(deps): update boto3 requirement in /lambdas/aurora-pgvector-init

Updates the requirements on [boto3](https://github.com/boto/boto3) to permit the latest version.
- [Release notes](https://github.com/boto/boto3/releases)
- [Commits](https://github.com/boto/boto3/compare/1.43.46...1.43.51)

---
updated-dependencies:
- dependency-name: boto3
  dependency-version: 1.43.51
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>

* build(deps): update boto3 requirement in /lambdas/suggestions

Updates the requirements on [boto3](https://github.com/boto/boto3) to permit the latest version.
- [Release notes](https://github.com/boto/boto3/releases)
- [Commits](https://github.com/boto/boto3/compare/1.43.46...1.43.51)

---
updated-dependencies:
- dependency-name: boto3
  dependency-version: 1.43.51
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>

* build(deps): update boto3 requirement in /lambdas/pdf-extract

Updates the requirements on [boto3](https://github.com/boto/boto3) to permit the latest version.
- [Release notes](https://github.com/boto/boto3/releases)
- [Commits](https://github.com/boto/boto3/compare/1.43.46...1.43.51)

---
updated-dependencies:
- dependency-name: boto3
  dependency-version: 1.43.51
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>

* build(deps): update boto3 requirement in /lambdas/pdf-generate

Updates the requirements on [boto3](https://github.com/boto/boto3) to permit the latest version.
- [Release notes](https://github.com/boto/boto3/releases)
- [Commits](https://github.com/boto/boto3/compare/1.43.46...1.43.51)

---
updated-dependencies:
- dependency-name: boto3
  dependency-version: 1.43.51
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>

* build(deps): bump the web group in /web with 3 updates

Bumps the web group in /web with 3 updates: [lucide-react](https://github.com/lucide-icons/lucide/tree/HEAD/packages/lucide-react), [react-hook-form](https://github.com/react-hook-form/react-hook-form) and [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite).


Updates `lucide-react` from 1.24.0 to 1.25.0
- [Release notes](https://github.com/lucide-icons/lucide/releases)
- [Commits](https://github.com/lucide-icons/lucide/commits/1.25.0/packages/lucide-react)

Updates `react-hook-form` from 7.81.0 to 7.82.0
- [Release notes](https://github.com/react-hook-form/react-hook-form/releases)
- [Changelog](https://github.com/react-hook-form/react-hook-form/blob/master/CHANGELOG.md)
- [Commits](https://github.com/react-hook-form/react-hook-form/compare/v7.81.0...v7.82.0)

Updates `vite` from 8.1.4 to 8.1.5
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/main/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/v8.1.5/packages/vite)

---
updated-dependencies:
- dependency-name: lucide-react
  dependency-version: 1.25.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: web
- dependency-name: react-hook-form
  dependency-version: 7.82.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: web
- dependency-name: vite
  dependency-version: 8.1.5
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: web
...

Signed-off-by: dependabot[bot] <support@github.com>

* build(deps): bump the mobile-npm group in /mobile with 4 updates

Bumps the mobile-npm group in /mobile with 4 updates: [@react-navigation/bottom-tabs](https://github.com/react-navigation/react-navigation/tree/HEAD/packages/bottom-tabs), [@react-navigation/native](https://github.com/react-navigation/react-navigation/tree/HEAD/packages/native), [@react-navigation/native-stack](https://github.com/react-navigation/react-navigation/tree/HEAD/packages/native-stack) and [react-native-screens](https://github.com/software-mansion/react-native-screens).


Updates `@react-navigation/bottom-tabs` from 7.18.8 to 7.18.11
- [Release notes](https://github.com/react-navigation/react-navigation/releases)
- [Changelog](https://github.com/react-navigation/react-navigation/blob/@react-navigation/bottom-tabs@7.18.11/packages/bottom-tabs/CHANGELOG.md)
- [Commits](https://github.com/react-navigation/react-navigation/commits/@react-navigation/bottom-tabs@7.18.11/packages/bottom-tabs)

Updates `@react-navigation/native` from 7.3.8 to 7.3.11
- [Release notes](https://github.com/react-navigation/react-navigation/releases)
- [Changelog](https://github.com/react-navigation/react-navigation/blob/@react-navigation/native@7.3.11/packages/native/CHANGELOG.md)
- [Commits](https://github.com/react-navigation/react-navigation/commits/@react-navigation/native@7.3.11/packages/native)

Updates `@react-navigation/native-stack` from 7.17.10 to 7.18.3
- [Release notes](https://github.com/react-navigation/react-navigation/releases)
- [Changelog](https://github.com/react-navigation/react-navigation/blob/@react-navigation/native-stack@7.18.3/packages/native-stack/CHANGELOG.md)
- [Commits](https://github.com/react-navigation/react-navigation/commits/@react-navigation/native-stack@7.18.3/packages/native-stack)

Updates `react-native-screens` from 4.26.0 to 4.26.2
- [Release notes](https://github.com/software-mansion/react-native-screens/releases)
- [Commits](https://github.com/software-mansion/react-native-screens/compare/4.26.0...4.26.2)

---
updated-dependencies:
- dependency-name: "@react-navigation/bottom-tabs"
  dependency-version: 7.18.11
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: mobile-npm
- dependency-name: "@react-navigation/native"
  dependency-version: 7.3.11
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: mobile-npm
- dependency-name: "@react-navigation/native-stack"
  dependency-version: 7.18.3
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: mobile-npm
- dependency-name: react-native-screens
  dependency-version: 4.26.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: mobile-npm
...

Signed-off-by: dependabot[bot] <support@github.com>

* build(deps): update boto3 requirement in /lambdas/library-ingest

Updates the requirements on [boto3](https://github.com/boto/boto3) to permit the latest version.
- [Release notes](https://github.com/boto/boto3/releases)
- [Commits](https://github.com/boto/boto3/compare/1.43.46...1.43.51)

---
updated-dependencies:
- dependency-name: boto3
  dependency-version: 1.43.51
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>

* Bump the api group with 7 updates

Bumps Microsoft.AspNetCore.Authentication.JwtBearer from 8.0.28 to 8.0.29
Bumps Microsoft.EntityFrameworkCore from 8.0.28 to 8.0.29
Bumps Microsoft.EntityFrameworkCore.Design from 8.0.28 to 8.0.29
Bumps Microsoft.EntityFrameworkCore.InMemory from 8.0.28 to 8.0.29
Bumps Microsoft.EntityFrameworkCore.Sqlite from 8.0.28 to 8.0.29
Bumps Microsoft.Extensions.Diagnostics.HealthChecks.EntityFrameworkCore from 8.0.28 to 8.0.29
Bumps Microsoft.NET.Test.Sdk from 18.7.0 to 18.8.1

---
updated-dependencies:
- dependency-name: Microsoft.AspNetCore.Authentication.JwtBearer
  dependency-version: 8.0.29
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: api
- dependency-name: Microsoft.EntityFrameworkCore
  dependency-version: 8.0.29
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: api
- dependency-name: Microsoft.EntityFrameworkCore.Design
  dependency-version: 8.0.29
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: api
- dependency-name: Microsoft.EntityFrameworkCore.InMemory
  dependency-version: 8.0.29
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: api
- dependency-name: Microsoft.EntityFrameworkCore.Sqlite
  dependency-version: 8.0.29
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: api
- dependency-name: Microsoft.Extensions.Diagnostics.HealthChecks.EntityFrameworkCore
  dependency-version: 8.0.29
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: api
- dependency-name: Microsoft.NET.Test.Sdk
  dependency-version: 18.8.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: api
...

Signed-off-by: dependabot[bot] <support@github.com>

* Bump NSubstitute from 5.3.0 to 6.0.0

---
updated-dependencies:
- dependency-name: NSubstitute
  dependency-version: 6.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-21 15:51:33 -04:00
Adam Moussa
cac4384f0d
feat(api): Phase 6 — optimistic concurrency (SHOC contract) + atomic audit staging (#226) 2026-07-14 01:18:30 -04:00
Adam Moussa
efcb13838e
refactor(web): domain-layer restructure (SHOC layering) + react-hook-form (#223)
* feat(web): adopt SHOC design system and shell layout (ADR 0003)

Port shoc-frontend-new dev's design system with its CSS-variable
single-token-source mechanism:

- src/styles/theme.css: SHOC token file ported verbatim (Montserrat/
  DM Sans/JetBrains Mono, primary #1c75bc, navy #262262, full radius/
  shadow/sidebar/header token layers); fonts self-hosted via @fontsource
- src/lib/theme/{css-vars,mui-theme}.ts: getCssVar -> createTheme
  adapter mirroring SHOC's mui-theme.ts (palette, typography, shadows
  tuple, component overrides; MUI v9 slot renames expressed as class
  selectors); theme.ts is now a re-export
- Shell: SHOC composition (sidebar column + sticky gradient topbar +
  scrolling main); sidebar 244px/76px collapse with brand header row,
  grouped nav, SHOC active treatment (white card + 3px accent bar);
  topbar 100-degree gradient, surface hamburger, gradient avatar pill
- Brand: SeahavenMark + BrandLockup ported (Tailwind re-expressed as
  sx; wordmark subtitle localized to PROPOSAL SYSTEM)
- Login: SHOC auth-card treatment (centered 384px card on #f9fafb)
- Old "Sea Haven Ops" Inter/#2563EB theme and Nunito remnants removed;
  remaining hardcoded hexes replaced with tokens; lucide-react for
  shell/nav icons per SHOC convention

Verify: tsc clean, 26/26 vitest, vite build OK; Playwright screenshots
pixel-sampled against the extracted SHOC spec (all hard values exact,
no blocking deviations).

* feat(contracts): adopt shared api-contracts in web, add zod schemas and ProblemDetails codes

Closes WEB-M5 (web hand-duplicated wire types, standing drift risk):

- shared/api-contracts: rewritten as the authoritative superset of the
  .NET DTOs (ProposalListItem/ProposalDetail with poNumber and
  submittedByName, line item requests, customers, pricing library,
  dashboard, audit, sites, auth, presigned upload, ApiProblem); stale
  Proposal/UpdateLineItemsRequest shapes removed
- shared/api-contracts/src/schemas.ts: zod runtime schemas coupled to
  every wire type via `satisfies z.ZodType<T>` (schema/type drift is now
  a compile error); separate entrypoint so type-only consumers (mobile)
  never pull zod
- web: imports @proposal-system/api-contracts (file: dep + tsconfig
  paths + vite preserveSymlinks); all 7 lib/api modules re-export shared
  types so page imports stay stable; enum unions tightened
  (PricingLibraryPage form state now ServiceCategory-typed)
- fix(web): customer create/update sent a singular `address` field the
  API silently dropped (contract is addresses: string[], CustomerDtos.cs)
  - addresses now round-trip, extra addresses preserved on edit
- api: ProblemDetails responses carry a machine-readable top-level
  `code` (SHOC error-code vocabulary): ValidationFailed,
  InvalidStateTransition, NotFound, Unauthorized, InternalError; new
  BusinessRuleException(code, message) maps to 422 with its code;
  GlobalExceptionHandlerTests cover the full mapping (wire contract)

Cross-checked .NET DTOs vs TS types vs zod schemas with the
orchestrator scanner (Gemini): core domains consistent; internal-only
DTOs (FileDtos vendor/lambda surface, SimilarProposalDtos, UserDtos
admin surface) intentionally uncovered.

Verify: dotnet 166/166, web tsc + vitest 26/26 + build, mobile tsc,
shared tsc all green.

* feat(web): domain-layer conventions doc + react-hook-form deps (Phase 4 prep)

* feat(web): scaffold domain module layer (proposals, lineItems, customers, pricingLibrary, admin, sites)

Additive-only: pages still use lib/api/* and constants/queryKeys.ts until
the page-migration agents run. Each domain ships api.ts (HTTP moved from
lib/api), types.ts (contract re-exports + view types), schemas.ts (contract
schema re-exports + form schemas with toRequest mappers), and use-cases.ts
(TanStack Query v5 hooks + hierarchical query keys, mirroring current page
invalidations and toast-on-error behavior).

Adds an explicit vite/vitest alias for the
@proposal-system/api-contracts/schemas subpath (package has no exports map)
plus a schema/mapper smoke test suite.

* refactor(web): proposal pages on domain layer, proposal form on react-hook-form

* refactor(web): admin workspace on domain layer

* refactor(web): customer management on domain layer + react-hook-form

* refactor(web): pricing library on domain layer + react-hook-form

* refactor(web): dashboards on domain layer

* test(web): domain use-case hook coverage

* refactor(web): finish domain-layer integration — migrate straggler components, delete legacy api modules

- SimilarProposalsPanel -> useSimilarProposals (domain/admin); inline
  SimilarProposal type replaced by domain/admin/types (identical shape);
  query key joins the admin hierarchical key space
- LineItemEditor type imports -> domain/lineItems/types
- Delete now-orphaned lib/api/{proposals,lineItems,customers,
  pricingLibrary,admin,sites}.ts, constants/queryKeys.ts,
  hooks/usePaginatedList.ts (lib/api/client.ts + auth.ts stay per
  domain README rule 5)

Verify: tsc clean, vitest 52/52, build OK, Playwright smoke of the
authed shell renders on domain hooks.

* fix(web): apply Phase 4 code-review findings (10 correctness + 4 cleanup)

Correctness:
- State-transition mutations now invalidate every cached view via
  invalidateProposalViews (detail + line items + lists + stats + admin
  dashboard) — approving no longer leaves a stale queue for the
  5-minute staleTime
- Presigned S3 PUT moved to proposals/api.ts with res.ok check — a
  rejected upload is no longer confirmed as uploaded
- toCustomerRequest always sends contactEmail ('' clears); API create
  path normalizes empty->null to match the update path — customer
  emails can now be cleared from the UI
- Shared Number-based numeric form fields (domain/shared/formFields):
  '12abc' no longer silently coerces to 12 in the pricing library
- Customer create/update invalidate customersKeys.all so cached search
  autocompletes see new customers
- AdminWorkspace clears dirty right after a successful implicit save,
  before approve — no false unsaved-changes prompt when approve fails
- ProposalFormPage submit gate and missing-fields caption derive from
  ONE checks list (missing customer is now listed)
- Empty states gated on !err in ProposalListPage/AdminDashboard — no
  contradictory error + 'no proposals' UI
- VendorDataPanel migrated to useVendorProposals (kills the divergent
  ['vendorProposals', id] cache key and the inline apiClient query)
- useCustomerList/usePricingLibraryList get keepPreviousData — no
  TablePagination out-of-range flash on page change

Cleanup:
- Dead speculative hooks removed (useCreate/BulkUpdate/DeleteLineItem,
  useUpdateProposal, useProposalHistory/Audit, lineItemRowFormSchema,
  toUpdateLineItemEntry); tests moved to the live save path
  (useSaveProposalWorkspace)
- Shared useDebouncedValue hook replaces 4 drifted inline debounce
  copies (one leaked its timer on unmount, two hardcoded 300ms);
  DEBOUNCE_AUTOCOMPLETE=300 named
- Fix: WEB-H5 / WEB-H6 finding-ID markers restored at the relocated
  onError handlers (CLAUDE.md traceability)
- shared/api-contracts gains an exports map; /schemas resolver alias
  deduplicated from 3 copies to the tsconfig paths mapping

Verify: tsc clean, vitest 51/51 (tests updated to pin the new
invalidation/mapper behavior + new '12abc' rejection test),
vite build OK, dotnet 166/166.
2026-07-14 00:11:11 +00:00
Adam Moussa
dfaee830f7
feat(contracts): shared api-contracts adoption, zod schemas, ProblemDetails codes (#222)
* feat(web): adopt SHOC design system and shell layout (ADR 0003)

Port shoc-frontend-new dev's design system with its CSS-variable
single-token-source mechanism:

- src/styles/theme.css: SHOC token file ported verbatim (Montserrat/
  DM Sans/JetBrains Mono, primary #1c75bc, navy #262262, full radius/
  shadow/sidebar/header token layers); fonts self-hosted via @fontsource
- src/lib/theme/{css-vars,mui-theme}.ts: getCssVar -> createTheme
  adapter mirroring SHOC's mui-theme.ts (palette, typography, shadows
  tuple, component overrides; MUI v9 slot renames expressed as class
  selectors); theme.ts is now a re-export
- Shell: SHOC composition (sidebar column + sticky gradient topbar +
  scrolling main); sidebar 244px/76px collapse with brand header row,
  grouped nav, SHOC active treatment (white card + 3px accent bar);
  topbar 100-degree gradient, surface hamburger, gradient avatar pill
- Brand: SeahavenMark + BrandLockup ported (Tailwind re-expressed as
  sx; wordmark subtitle localized to PROPOSAL SYSTEM)
- Login: SHOC auth-card treatment (centered 384px card on #f9fafb)
- Old "Sea Haven Ops" Inter/#2563EB theme and Nunito remnants removed;
  remaining hardcoded hexes replaced with tokens; lucide-react for
  shell/nav icons per SHOC convention

Verify: tsc clean, 26/26 vitest, vite build OK; Playwright screenshots
pixel-sampled against the extracted SHOC spec (all hard values exact,
no blocking deviations).

* feat(contracts): adopt shared api-contracts in web, add zod schemas and ProblemDetails codes

Closes WEB-M5 (web hand-duplicated wire types, standing drift risk):

- shared/api-contracts: rewritten as the authoritative superset of the
  .NET DTOs (ProposalListItem/ProposalDetail with poNumber and
  submittedByName, line item requests, customers, pricing library,
  dashboard, audit, sites, auth, presigned upload, ApiProblem); stale
  Proposal/UpdateLineItemsRequest shapes removed
- shared/api-contracts/src/schemas.ts: zod runtime schemas coupled to
  every wire type via `satisfies z.ZodType<T>` (schema/type drift is now
  a compile error); separate entrypoint so type-only consumers (mobile)
  never pull zod
- web: imports @proposal-system/api-contracts (file: dep + tsconfig
  paths + vite preserveSymlinks); all 7 lib/api modules re-export shared
  types so page imports stay stable; enum unions tightened
  (PricingLibraryPage form state now ServiceCategory-typed)
- fix(web): customer create/update sent a singular `address` field the
  API silently dropped (contract is addresses: string[], CustomerDtos.cs)
  - addresses now round-trip, extra addresses preserved on edit
- api: ProblemDetails responses carry a machine-readable top-level
  `code` (SHOC error-code vocabulary): ValidationFailed,
  InvalidStateTransition, NotFound, Unauthorized, InternalError; new
  BusinessRuleException(code, message) maps to 422 with its code;
  GlobalExceptionHandlerTests cover the full mapping (wire contract)

Cross-checked .NET DTOs vs TS types vs zod schemas with the
orchestrator scanner (Gemini): core domains consistent; internal-only
DTOs (FileDtos vendor/lambda surface, SimilarProposalDtos, UserDtos
admin surface) intentionally uncovered.

Verify: dotnet 166/166, web tsc + vitest 26/26 + build, mobile tsc,
shared tsc all green.

* fix(web): install shared api-contracts deps via postinstall

Web Frontend Check failed on PR #222: tsc compiles
shared/api-contracts/src/schemas.ts through the tsconfig path alias,
and module resolution for its zod import walks up from shared/, never
reaching web/node_modules. CI only ran npm ci in web/, so the shared
package's deps were absent. A postinstall hook installs them wherever
web's deps are installed (CI typecheck, web-test, deploy bundling).

Passed locally only because a stray repo-root node_modules/zod
satisfied the lookup.
2026-07-13 19:28:33 -04:00
dependabot[bot]
cac18d6b16
Bump the api group with 1 update (#192) 2026-07-04 14:10:10 -04:00
dependabot[bot]
433198c4e8
Bump xunit.runner.visualstudio from 2.8.2 to 3.1.5 (#162)
---
updated-dependencies:
- dependency-name: xunit.runner.visualstudio
  dependency-version: 3.1.5
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-22 19:47:23 +00:00
dependabot[bot]
b1a330e916
Bump Microsoft.NET.Test.Sdk from 17.14.1 to 18.6.0 (#160)
---
updated-dependencies:
- dependency-name: Microsoft.NET.Test.Sdk
  dependency-version: 18.6.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-22 19:40:47 +00:00
dependabot[bot]
63adfdf816
Bump AWSSDK.SimpleEmailV2 from 3.7.500 to 3.7.509.10 (#155)
---
updated-dependencies:
- dependency-name: AWSSDK.SimpleEmailV2
  dependency-version: 3.7.509.10
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: api
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-22 13:39:27 -04:00
dependabot[bot]
3c17c33c16
Bump Amazon.Lambda.AspNetCoreServer.Hosting and 14 others (#149)
Some checks failed
Deploy / Deploy to AWS (push) Has been cancelled
Bumps Amazon.Lambda.AspNetCoreServer.Hosting from 1.7.2 to 1.10.0
Bumps AWSSDK.DynamoDBv2 from 3.7.400 to 3.7.513.4
Bumps AWSSDK.Extensions.NETCore.Setup from 3.7.400 to 3.7.400.2
Bumps AWSSDK.S3 from 3.7.405 to 3.7.511.8
Bumps AWSSDK.SecretsManager from 3.7.500 to 3.7.504.43
Bumps AWSSDK.SQS from 3.7.500 to 3.7.502.57
Bumps FluentAssertions from 7.2.0 to 7.2.2
Bumps FluentValidation from 11.11.0 to 11.12.0
Bumps Microsoft.AspNetCore.Authentication.JwtBearer from 8.0.27 to 8.0.28
Bumps Microsoft.EntityFrameworkCore from 8.0.27 to 8.0.28
Bumps Microsoft.EntityFrameworkCore.Design from 8.0.11 to 8.0.28
Bumps Microsoft.EntityFrameworkCore.InMemory from 8.0.11 to 8.0.28
Bumps Microsoft.EntityFrameworkCore.Sqlite from 8.0.11 to 8.0.28
Bumps Microsoft.Extensions.Diagnostics.HealthChecks.EntityFrameworkCore from 8.0.27 to 8.0.28
Bumps Microsoft.NET.Test.Sdk from 17.12.0 to 17.14.1

---
updated-dependencies:
- dependency-name: Amazon.Lambda.AspNetCoreServer.Hosting
  dependency-version: 1.10.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: api
- dependency-name: AWSSDK.DynamoDBv2
  dependency-version: 3.7.513.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: api
- dependency-name: AWSSDK.Extensions.NETCore.Setup
  dependency-version: 3.7.400.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: api
- dependency-name: AWSSDK.S3
  dependency-version: 3.7.511.8
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: api
- dependency-name: AWSSDK.SecretsManager
  dependency-version: 3.7.504.43
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: api
- dependency-name: AWSSDK.SQS
  dependency-version: 3.7.502.57
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: api
- dependency-name: FluentValidation
  dependency-version: 11.12.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: api
- dependency-name: Microsoft.AspNetCore.Authentication.JwtBearer
  dependency-version: 8.0.28
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: api
- dependency-name: Microsoft.EntityFrameworkCore
  dependency-version: 8.0.28
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: api
- dependency-name: Microsoft.EntityFrameworkCore.Design
  dependency-version: 8.0.28
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: api
- dependency-name: Microsoft.Extensions.Diagnostics.HealthChecks.EntityFrameworkCore
  dependency-version: 8.0.28
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: api
- dependency-name: FluentAssertions
  dependency-version: 7.2.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: api
- dependency-name: Microsoft.EntityFrameworkCore.InMemory
  dependency-version: 8.0.28
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: api
- dependency-name: Microsoft.EntityFrameworkCore.Sqlite
  dependency-version: 8.0.28
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: api
- dependency-name: Microsoft.NET.Test.Sdk
  dependency-version: 17.14.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: api
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-18 16:13:33 -04:00
Adam Moussa
5d84399a0d
feat: pricing library — curated priced items feed the RAG corpus (#127)
Some checks are pending
Deploy / Deploy to AWS (push) Waiting to run
Adds a managed pricing library so admins can seed/curate reference priced items
directly, instead of the corpus being populated only by ingesting Sent proposals.
v1 PR5.

API:
- PricingLibraryItem entity + migration; /api/pricing-library CRUD (admin), with
  GET {id} reachable by internal Lambda callers (admins role via internal key).
- Create/update publish an ADDITIVE library-ingest SQS job {pricingLibraryItemId},
  wrapped so a publish failure never rolls back the save.

Lambda (library-ingest):
- Additive event-shape branch: pricingLibraryItemId -> fetch item, format markdown,
  upload to pricing-library/{category}/{id}.md, trigger KB sync. The existing
  proposalId path is byte-for-byte unchanged. Explicit error when neither id present;
  warns when both present.

Web:
- Pricing Library management page (/admin/pricing-library): list / create / edit / delete.

GPT-4.1 cross-review on the event-shape change: no BLOCK (neither/both-id handling
applied). Verified: api 159 tests; web tsc + 26 tests; lambdas ruff + 37 pytest.
2026-06-18 12:49:47 -04:00
Adam Moussa
1fca0fa978
feat: proposal delivery — email customers the PDF on Mark as Sent (#126)
* feat: proposal delivery — email customers the PDF on "Mark as Sent"

Makes the system's namesake feature real: marking a proposal Sent now emails the
customer an expiring link to the branded PDF, and customers are managed (with
contact emails) instead of hardcoded. v1 PR4.

API:
- Customer.ContactEmail + migration; Customer list/update endpoints. Search stays
  additive at GET /api/customers?query= (frozen-mobile + web compat); new paginated
  list at GET /api/customers/list (admin).
- IEmailService (SesEmailService v2 / DevEmailService, dev-gated). MarkSentAsync
  resolves the customer's email, presigns the latest PDF (7d), and sends via SES.
  Email/presign failures are caught + audited and NEVER roll back the Sent transition.
- Startup EF migration guarded by a Postgres advisory lock (concurrency-safe).

Infra:
- SES email identity (proposals@seahavenind.com); least-privilege ses:SendEmail/
  SendRawEmail scoped to the identity ARN + ses:FromAddress condition; SES_FROM_ADDRESS
  env. SES starts in sandbox — production access needed for unverified recipients.

Web:
- Customer management page (/admin/customers): list / create / edit incl. contact email.
- New-proposal form searches real customers (free-solo) instead of a hardcoded value.
- Mark-as-Sent dialog notes the PDF will be emailed to the customer.

GPT-4.1 cross-review (SES IAM): no BLOCK (ses:FromAddress condition applied).
Verified: api build + 121 tests; web tsc + 26 tests; infra tsc; ruff clean.

* Potential fix for pull request finding 'CodeQL / Exposure of private information'

Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>

* Potential fix for pull request finding 'CodeQL / Exposure of private information'

Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>

* Potential fix for pull request finding 'CodeQL / Exposure of private information'

Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>

---------

Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
2026-06-18 12:40:55 -04:00
Adam Moussa
ae3ad9d823 fix: CORS, JWT auth, useBlocker crash, and auto-migration for production deploy
Some checks failed
Deploy / Deploy to AWS (push) Has been cancelled
- Add CloudFront origin to API Gateway CORS preflight and .NET CORS policy
- Replace HttpMethod.ANY with explicit methods so OPTIONS preflight doesn't
  hit the JWT authorizer (was causing 403 on all API calls)
- Return Cognito ID token instead of access token from auth callback
  (access tokens lack the aud claim required by API Gateway JWT authorizer)
- Add CloudFront callback URI to allowed redirect list
- Remove identity_provider=Google from login URL to show Cognito hosted UI
- Replace useBlocker (requires data router) with state-based navigation guard
  to fix crash on AdminWorkspace with BrowserRouter
- Add auto-migration on Lambda cold start
- Enable Swagger in production
2026-05-27 19:20:29 -04:00
Adam Moussa
ab9569d7a9 test: add ProposalNumberGenerator, LineItemService state guard, and API client interceptor tests
- ProposalNumberGenerator tests (8 tests): format validation (SHI-YYYY-NNNN),
  sequence incrementing, revision skipping, year boundary isolation, uniqueness,
  zero-padding, high sequence rollover. Uses SQLite in-memory with Postgres
  function stubs to support ExecuteSqlRawAsync.

- LineItemService state guard tests (18 tests): verifies line items cannot be
  created/bulk-updated/deleted on Approved or Sent proposals (QA-C2), confirms
  operations succeed on InReview and Revised statuses, validates
  KeyNotFoundException on missing proposals, verifies audit logging.

- API client interceptor tests (14 tests): request interceptor attaches Bearer
  token from sessionStorage (WEB-C1), handles missing/malformed token data,
  response interceptor dispatches Redux logout on 401 (WEB-M2), returns friendly
  messages for 403/404, extracts server error details, handles network errors.

- DbContextFactory updated to suppress InMemoryEventId.TransactionIgnoredWarning
  so BulkUpdateAsync tests work with in-memory provider.

- Added SqliteDbContextFactory for tests requiring relational features.

- Added Microsoft.EntityFrameworkCore.Sqlite to test project dependencies.

Total: 104 .NET tests (was 77), 26 web tests (was 12). CI already wired.
2026-05-27 18:18:44 -04:00
Adam Moussa
8d73e66a17 fix(api): API-M2, M5, M7, M9, M10, M12, M13 — Medium audit findings
- API-M2: Add comment for fail-loud auth config guard (already implemented)
- API-M5: Add FluentValidation validators for VendorProposal, GeneratedPdf,
  and SimilarReference DTOs; move request records to Application DTOs
- API-M7: Add AsNoTracking() to all read-only queries in ProposalService,
  LineItemService, AdminController, UsersController, FilesController
- API-M9: Log stderr from dev PDF generation instead of returning to client
- API-M10: Return generic "Authentication service unavailable" in auth
  callbacks instead of leaking Cognito/DevMode configuration state
- API-M12: Enrich audit logging with before/after values for status changes,
  proposal edits, and line item operations using structured JSON
- API-M13: Log previous role alongside new role on user role changes in
  both UsersController and Cognito-synced role updates in AuthController
2026-05-27 18:18:44 -04:00
Adam Moussa
42fe0823b0 fix: API medium findings (API-M3, M4, M6, M8, M11, M14)
- API-M3: Add dispatcher ownership check on line item reads
- API-M4: Add dispatcher ownership check on PDF endpoints
- API-M6: Add 25 MB file size validation on presigned upload URLs
- API-M8: Wrap BulkUpdate delete-all/insert-all in explicit transaction
- API-M11: Replace silent catch blocks with logged exceptions in
  LineItemService and ProposalService
- API-M14: Validate dev signing key is present (from user-secrets or
  env vars) instead of using null-forgiving operator
2026-05-27 18:18:44 -04:00
Adam Moussa
01fe003a6d fix: wire test suites into CI, fix stale tests from Phase 1-2 fixes
- Add web-test job (vitest) and python-test job (pytest) to CI workflow
- dotnet reusable workflow already runs tests by default
- Update InternalApiKeyMiddleware tests for API-C1/API-H1 fixes:
  invalid key now returns 401 (not pass-through), valid key on
  disallowed path returns 403
- Fix suggestions test: include status field for LAM-H4 idempotency guard
- Total: 108 tests (77 .NET, 12 web, 19 Python) all passing
2026-05-27 18:18:44 -04:00
Adam Moussa
9c04ba4756 fix: resolve test compile errors from merge, update AUDIT-REPORT.md
Fix CreateProposalRequest constructor calls (missing PoNumber param)
and ProposalService constructor (missing ILogger param) that diverged
when test-bootstrap and api-hardening worktrees merged.

Mark all Critical and High findings as fixed in AUDIT-REPORT.md with
remediation status for each phase.
2026-05-27 18:18:44 -04:00
Adam Moussa
d21b1c5edb test: bootstrap test infrastructure with critical coverage (QA-C1 through QA-C6)
QA-C1: Create xUnit test project, add to solution, wire dependencies
- api/tests/ProposalSystem.Tests with xUnit + FluentAssertions + NSubstitute
- InMemory EF Core provider for isolated DB tests

QA-C2: Proposal state machine transition tests (16 tests)
- Valid: InReview->Approved, Approved->Sent, Sent->Revised
- Invalid: InReview->Sent, Approved->Revised, Draft->Approved, etc.
- Edge cases: idempotency, missing line items, revision line item copying
- Audit and job publisher verification

QA-C3: Authorization attribute tests (16 tests)
- Controller-level [Authorize] on all controllers except AuthController
- Role requirements: admins/sysadmins on admin actions
- Dispatcher exclusion from admin/sysadmin routes
- SysAdmin-only user management enforcement

QA-C4: InternalApiKeyMiddleware tests (8 tests)
- Valid key sets claims and calls next
- Invalid key passes through to JWT (no 401/403)
- Missing key/empty config disables middleware
- Documents API-C1 vulnerability (key works on any path)

QA-C5: ProtectedRoute and RoleGuard tests (12 tests, vitest)
- ProtectedRoute: renders children when authenticated, redirects when not
- RoleGuard: role-based access, dispatcher/admin/sysadmin enforcement
- authSlice: setUser, logout, expired token handling

QA-C6: Lambda SQS handler tests (19 tests, pytest)
- pdf-generate: batch processing, failure reporting, malformed body
- suggestions: batch processing, proposal-not-found skip, AI item preservation
- API key caching, retry helpers

Total: 107 tests (76 .NET + 12 web + 19 Python), all passing.
2026-05-27 18:18:44 -04:00
Adam Moussa
2017c0379e fix: API-H2 validate redirectUri, API-H6 add structured logging to services
API-H2: Validate redirectUri against an allowlist before exchanging the
authorization code with Cognito. Production URI is always allowed;
localhost is only allowed when Auth:DevMode is true.

API-H6: Inject ILogger<T> into ProposalService and LineItemService.
Log state transitions (approve, send, revise) at Information level,
invalid state transition attempts at Warning level, and caught
exceptions (audit/job publisher failures) at Error level.
2026-05-27 18:18:44 -04:00
Adam Moussa
4f1271eb50 audit: fix all Critical and High security/reliability issues across monorepo
6-domain audit (API, web, mobile, lambdas, infra, QA) with fixes:

API security: scope internal API key middleware to allowed paths only,
return 401 on invalid key instead of falling through, remove unvalidated
JWT code path, sanitize error messages, add UpdateProposal validator,
remove status field from UpdateProposalRequest to prevent over-posting,
log swallowed exceptions in ProposalService.

Infrastructure: enforce SSL on all S3 buckets, encrypt SQS queues,
enable optional MFA on Cognito, add API Gateway access logging.

Lambdas: fix _retry_request undefined variable across all 4 Lambdas,
re-raise exceptions in pdf-extract/pdf-generate instead of swallowing,
add idempotency guard to suggestions Lambda.

Web: add ErrorBoundary, add auth loading state to ProtectedRoute,
add mutation error toasts in AdminWorkspace, fix dead Cognito link.

Mobile: add mutex to offline queue processing, distinguish permanent
vs retryable failures, register all screens for both roles, log sync
errors.

Swagger/OpenAPI: add Swashbuckle with JWT bearer security definition,
add ProducesResponseType attributes to key endpoints.

Includes AUDIT-REPORT.md with complete findings and CLAUDE.md project
instructions.
2026-05-27 18:18:44 -04:00
Adam Moussa
ef052a81ac Add role-aware dashboard stats and recent proposals
GetStatsAsync now returns global counts for admins/sysadmins instead of
filtering by submitter. Dashboard recent proposals query uses mine=false
for admins so they see all proposals, not just their own.
2026-05-27 18:17:48 -04:00
Adam Moussa
6de4bafec4 Add revision dropdown, editable WO#, and fix Revised proposal approval
- Fix: ApproveAsync now accepts both InReview and Revised proposals
- Revision dropdown in header: navigate between revisions, download PDF per rev
- Work Order Number editable in admin workspace (same pattern as PO#)
- Added WorkOrderNumber to UpdateProposalRequest DTO and service
- Info bar reordered: Customer, Site, WO#, PO#, Category, Priority
- Uniform font sizing across info bar (0.75rem labels, 0.875rem values)
- Typed getHistory API to return ProposalDetail[]
- Download PDF button in action bar for Sent/Revised proposals
2026-05-27 18:17:48 -04:00
Adam Moussa
cab97cbb1b Add PDF download for all roles, version history, and status timeline fix
- Removed admin-only restriction on PDF download endpoints
- Added GET pdf/versions endpoint returning all generated PDFs
- Download PDF button on detail page for Approved/Sent/Revised proposals
- PDF Versions card shows all revisions with individual download buttons
- Dev-mode support for GetPdfRevision endpoint
- Status timeline stepper now uses STATUS_LABELS (fixes "InReview" display)
- PDF Lambda improvements for local generation
2026-05-27 18:17:48 -04:00
Adam Moussa
9b502045dd Add site search, PO number, service category Other, and form enhancements
- Structured manual site entry with 5 separate address fields
- Site search via Autocomplete with server-side filtering
- Added PO number field to proposal form and AddPoNumber migration
- Added Other to ServiceCategory enum with custom category text input
- Label consistency: "Work Order #" → "Work Order Number", "PO Number"
- Top row reflow to 3-column layout (4/4/4)
- Dev PDF generation script for local testing
2026-05-27 18:17:48 -04:00
Adam Moussa
9d856a9619
Phase 3 audit fixes: FIX-01–47, accessibility NITs, code quality NITs [skip deploy]
Some checks failed
Deploy / Deploy to AWS (push) Has been cancelled
## Summary
Implements Phase 3 of the AUDIT-2026-05-20 findings:
- 29 FIX-severity items across API, web, infra, and lambdas
- 7 accessibility NITs (aria-labels, document titles)
- 4 code quality NITs (deduplication, constants extraction)

Key changes:
- API: N+1 fix, pagination clamping, idempotent transitions, upload confirm endpoint, revision TotalBidAmount carry-forward
- Web: confirmation dialogs, currency formatting, error states, date range filters, document titles
- Infra: S3 CORS lockdown, API Gateway throttling, AOSS network policy fix, CI concurrency
- Lambdas: skip empty suggestions, remove status side-effect
- Scripts: post-deploy health check

## Test plan
- [x] tsc --noEmit (web + infra)
- [x] dotnet build (api)
- [x] ruff check + format (lambdas)
- [x] Cross-review via orchestrator (no blockers)

[skip deploy]
2026-05-20 19:38:36 -04:00
Adam Moussa
99e0c16505 Merge main into feature/fix-phase-2, resolve infra conflicts
Keep both Phase 1 (JWT authorizer, webClientId/mobileClientId props) and
Phase 2 (alarmTopic, CloudWatch alarms) changes in CDK stacks.
2026-05-20 19:09:35 -04:00
Adam Moussa
184bc1da7e Fix Phase 2 audit findings: reliability, UX, and operational monitoring
BLOCK-10: Add CloudWatch alarms (DLQ, Lambda errors, RDS, API 5xx) with SNS email
BLOCK-11: Remove sync-over-async deadlock in CurrentUserService
BLOCK-12: Add AppDelegate OAuth URL callback handler for mobile
BLOCK-13: Wire mobile 401 interceptor to dispatch Redux logout
BLOCK-14: Fix JWT base64 padding crash and SysAdmin role detection
BLOCK-15: Reset pagination to page 1 on filter change
BLOCK-16: Add unsaved-changes guard (beforeunload + useBlocker) to AdminWorkspace
FIX-08: Add BulkUpdateLineItems FluentValidation validator
FIX-13: Display auth errors on LoginPage
FIX-25: Add token refresh with retry queue to mobile API client
FIX-44: Add httpx retry logic to all Lambda handlers
FIX-42/43: Align docker-compose PG version (15) and DB name (proposals) with RDS
2026-05-20 19:07:49 -04:00
Adam Moussa
091c5fcb44
Fix Phase 1 security and data integrity audit findings (#49)
BLOCK-01: Add API Gateway JWT authorizer with Cognito, route internal
Lambda calls through Function URL to bypass gateway auth
BLOCK-02/03: Prevent proposal number race condition with pg_advisory_xact_lock
and filter revision numbers from max-number query
BLOCK-04: Restrict VendorProposals and GeneratedPdfs to admins/sysadmins
BLOCK-05: Sum all vendor costs instead of overwriting with single vendor
BLOCK-06: Enable ValidateAudience on JWT, add Auth env vars to API Lambda
BLOCK-07: Validate ID token signature in AuthController via OIDC discovery
BLOCK-08: Use batchItemFailures in all Lambda SQS handlers
BLOCK-09: Increase SQS visibility timeout from 180s to 720s
FIX-10: Scope dispatcher queries to own proposals (IDOR fix)
2026-05-20 18:51:31 -04:00
Adam Moussa
866601025d Validate dev-login input: reject empty email and invalid role
Empty-string email passed model binding but created a ghost user with no
identity. Invalid role strings (e.g. "SuperHero") silently defaulted to
Admin, granting unintended elevated access.

Now returns 400 for both cases. Default role changed from Admin to
Dispatcher (least privilege).
2026-05-20 18:08:55 -04:00
Adam Moussa
d00c552497 Fix admin dashboard LINQ crash, revise unique constraint, and mutation response data
AdminController: Rewrite avgTurnaround query to fetch approved times to
memory before computing TotalHours — EF Core/Npgsql cannot translate
TimeSpan.TotalHours to SQL, causing a 409 on every dashboard load.

ProposalService.ReviseAsync: Append -R{n} suffix to revision's
ProposalNumber so it doesn't violate the unique index. Previously copied
the parent's number verbatim, causing a DbUpdateException (500).

ProposalService Update/Approve/MarkSent: Add .Include(p => p.SubmittedBy)
(and ApprovedBy where relevant) so MapToResponse returns submittedByName
instead of null. GetByIdAsync already had these includes.
2026-05-20 18:08:50 -04:00
Adam Moussa
9b97b7b578 Fix proposal workflow: scoped My Proposals, idempotent state transitions
Add Mine filter to ProposalFilterRequest so My Proposals page shows
only the current user's submissions regardless of role. Create
proposals directly as InReview (skip Draft) since form submission is
the review request. Make Approve, MarkSent, and Revise idempotent —
repeat calls return current state instead of throwing. Wrap line item
audit logging in try/catch so audit failures don't mask successful
saves.
2026-05-20 17:24:09 -04:00
Adam Moussa
f37c2aa3f0 Fix dev-login role switching, distinct users, and user resolution races
Dev-login now updates the role when an existing user logs in as a
different role. Each dev role maps to a distinct email/name so
sessions don't collide. CognitoSub is deterministic (email-based)
to prevent mismatch between dev-login and CurrentUserService.
CurrentUserService catches DbUpdateException on concurrent user
creation and retries the lookup instead of crashing.
2026-05-20 17:24:01 -04:00
Adam Moussa
f44caba906 Fix JSON enum serialization and audit log jsonb format
Add JsonStringEnumConverter so string enum values (ServiceCategory,
Priority, PricingMode, LineItemSource) deserialize correctly from
frontend requests. Wrap AuditService detail strings in a JSON object
to satisfy the Postgres jsonb column type. Relax global.json SDK
version to match installed 8.0.1xx feature band.
2026-05-20 17:23:55 -04:00
dependabot[bot]
3250d4d927
Bump Microsoft.Extensions.Diagnostics.HealthChecks.EntityFrameworkCore from 8.0.11 to 8.0.27 (#37)
---
updated-dependencies:
- dependency-name: Microsoft.Extensions.Diagnostics.HealthChecks.EntityFrameworkCore
  dependency-version: 8.0.27
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-18 19:37:30 +00:00
Adam Moussa
f051f74fde
Fix security gaps and improve code quality across API and Lambdas (#23)
Security: add system identity claims to InternalApiKeyMiddleware so
Lambda-to-API calls resolve a proper user, inject ICurrentUserService
into GeneratedPdfsController to replace Guid.Empty, and consolidate
CurrentUserService into a single ResolveAsync lookup chain.

Quality: replace four COUNT queries in ProposalService.GetStatsAsync
with a single grouped query, convert all Lambda print() to structured
logging, and add retry helpers for Lambda-to-API HTTP calls.
2026-05-17 13:48:14 -04:00
dependabot[bot]
36b39c73df
Bump FluentValidation.AspNetCore from 11.3.0 to 11.3.1 (#18)
---
updated-dependencies:
- dependency-name: FluentValidation.AspNetCore
  dependency-version: 11.3.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-17 17:14:36 +00:00
dependabot[bot]
3e43616e4a
Bump Microsoft.AspNetCore.Authentication.JwtBearer from 8.0.11 to 8.0.27 (#19)
---
updated-dependencies:
- dependency-name: Microsoft.AspNetCore.Authentication.JwtBearer
  dependency-version: 8.0.27
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-17 17:10:39 +00:00