Commit graph

263 commits

Author SHA1 Message Date
Adam Moussa
a74ac4945f fix: LAM-C1/INF-H1 require IAM auth on Function URL, INF-H3 restrict OpenSearch to VPC
LAM-C1/INF-H1: Change Function URL authType from NONE to AWS_IAM and
grant invokeUrl permission to all four caller Lambdas (suggestions,
pdf-extract, pdf-generate, library-ingest). Lambda HTTP clients will
need SigV4 signing as a follow-up.

INF-H3: Create OpenSearch Serverless VPC endpoint in private subnets
and update network policy from AllowFromPublic to SourceVPCEs, removing
public internet access to the vector search collection.
2026-05-27 18:18:44 -04:00
Adam Moussa
67b4732395 fix: WEB-C1 move JWT to sessionStorage, complete mutation error handling
- WEB-C1 (Critical): Replace all localStorage token operations with
  sessionStorage in authSlice.ts and client.ts. Tokens now clear when
  the browser tab closes, reducing the XSS token-theft window.
  httpOnly cookie migration documented as follow-up.
- WEB-M2: 401 interceptor now dispatches Redux logout() before
  redirect so auth state stays consistent with cleared storage.
- WEB-H5/H6: Add onError toast handlers to sendMutation,
  reviseMutation, and regenerateMutation in AdminWorkspace.
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
d15f6bfb95 workspace: sticky panels, action bar polish, breadcrumb nav, line item UX improvements 2026-05-27 18:18:44 -04:00
Adam Moussa
0c8ab31282 pages: users empty state card, form max-width, table display improvements 2026-05-27 18:18:44 -04:00
Adam Moussa
cfee6690c0 login: audit styling — gradient, card, button colors, descriptions 2026-05-27 18:18:39 -04:00
Adam Moussa
a6091344da dashboard: audit KPI styling, secondary context lines, page title consistency 2026-05-27 18:18:35 -04:00
Adam Moussa
2e20e7ad99 sidebar: audit styling updates, responsive collapse at 1200px/900px 2026-05-27 18:18:30 -04:00
Adam Moussa
f7b4ab6f93 theme: apply full UX audit token pass (palette, typography, shapes, component overrides) 2026-05-27 18:18:27 -04:00
Adam Moussa
d27cc2e528 style: switch to subtle tinted chips with borders, reduce urgent row prominence 2026-05-27 18:18:27 -04:00
Adam Moussa
cef0b611ba topbar: update avatar color, add DEV environment indicator pill 2026-05-27 18:18:24 -04:00
Adam Moussa
b21e5db08a Update login page colors to match refined app palette 2026-05-27 18:18:24 -04:00
Adam Moussa
3e131dbd00 Add worktrees to gitignore 2026-05-27 18:18:24 -04:00
Adam Moussa
b507bb0c28 Replace MUI semantic chip colors with custom status/priority palette 2026-05-27 18:18:24 -04:00
Adam Moussa
83e1a7948e Fix nested tbody in proposal tables: use Fragment instead of Box component="tbody" 2026-05-27 18:18:12 -04:00
Adam Moussa
b43bb64fff Consolidate hardcoded colors in Topbar and Sidebar to match refined palette 2026-05-27 18:18:12 -04:00
Adam Moussa
837aaa3db3 Update theme: Inter font, flat AppBar, refined palette, 6px radius, polished component defaults 2026-05-27 18:17:48 -04:00
Adam Moussa
594d3395c6 Add UX improvements: clickable KPIs, status tabs, revision grouping, workspace restructure, form sections
Medium-effort improvements:
- Shrink KPI cards and make each clickable (navigates to filtered list)
- Role-specific KPI labels (admin: All Proposals/Pending Review; dispatcher: Total Submitted/In Review)
- Reorder sidebar nav per role (admins see Admin section first)
- Add WO# and Priority columns to Dashboard recent proposals table
- Replace "View All" with "View All Proposals" button with arrow icon
- Add Age column to admin queue with color-coded staleness (>2d orange, >5d red)

Heavy-lift improvements:
- Status tabs on All Proposals page (replace status dropdown with All/In Review/Approved/Sent/Revised tabs)
- Group proposal revisions in tables (expand/collapse, latest shown by default)
- Collapsible left panel in admin workspace (chevron toggle, center panel expands to fill)
- Sticky action bar with total display, item count, vendor cost, compact unsaved-changes chip
- Restructure proposal form into 3 card sections (Job Details, Site & Location, Work Details)
- Disabled-submit helper text showing missing required fields
- Compact status timeline with timestamps under completed steps
- Status explanation below timeline (e.g., "Awaiting admin pricing and approval")
2026-05-27 18:17:48 -04:00
Adam Moussa
d583f99f5b Update session handoff with current state and remaining tasks
Consolidates all 7 commits (4 prior + 3 this session), organizes
remaining UX review items by effort level, and documents outstanding
infrastructure and mobile tasks.
2026-05-27 18:17:48 -04:00
Adam Moussa
85bed9a161 Apply UX quick wins from external review
- Replace $0.00 with "Not priced" via formatBidAmount helper
- Consistent login buttons with role descriptions
- Context-aware empty states (filter mismatch vs no data)
- Clear Filters button on proposal list and admin dashboard
- Rename "Regenerate" to "Regenerate Suggested Line Items"
- Add tooltips explaining disabled Save/Approve buttons
- Replace "RAG engine" jargon with plain language
- Improve User Management placeholder with Cognito guidance
- Add Puppeteer screenshot script for all roles/pages
2026-05-27 18:17:48 -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
edb557fb23 Fix layout double-offset from persistent drawer
The sidebar Drawer reserved width in the flex container AND the main
content had margin-left for the same width, pushing content 440px right.
Removed the redundant margin-left and added a width transition to the
Drawer for smooth toggle animation.
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
666e2bad9e Add status/priority display improvements, sortable tables, and list filters
- STATUS_LABELS map: InReview displays as "In Review" everywhere
- PRIORITY_LABELS map: Emergency → "Emergency Dispatch"
- Sent status color changed from green to blue (distinguishes from Approved)
- Urgent/Emergency rows get colored borders and icons
- All 8 columns in proposals list now sortable via TableSortLabel
- Status, Category, and Priority filter dropdowns with server-side filtering
- Filters reset pagination to page 1
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
dependabot[bot]
58a4a94d8f
Bump react-native-screens from 4.25.1 to 4.25.2 in /mobile (#62)
Some checks failed
Deploy Mobile (iOS) / Build & Upload to TestFlight (push) Has been cancelled
Deploy / Deploy to AWS (push) Has been cancelled
Bumps [react-native-screens](https://github.com/software-mansion/react-native-screens) from 4.25.1 to 4.25.2.
- [Release notes](https://github.com/software-mansion/react-native-screens/releases)
- [Commits](https://github.com/software-mansion/react-native-screens/compare/4.25.1...4.25.2)

---
updated-dependencies:
- dependency-name: react-native-screens
  dependency-version: 4.25.2
  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-23 04:36:15 +00:00
dependabot[bot]
257ea97613
Bump react and @types/react in /mobile (#65)
Bumps [react](https://github.com/facebook/react/tree/HEAD/packages/react) and [@types/react](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/react). These dependencies needed to be updated together.

Updates `react` from 19.2.3 to 19.2.6
- [Release notes](https://github.com/facebook/react/releases)
- [Changelog](https://github.com/facebook/react/blob/main/CHANGELOG.md)
- [Commits](https://github.com/facebook/react/commits/v19.2.6/packages/react)

Updates `@types/react` from 19.2.14 to 19.2.15
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/react)

---
updated-dependencies:
- dependency-name: react
  dependency-version: 19.2.6
  dependency-type: direct:production
  update-type: version-update:semver-patch
- dependency-name: "@types/react"
  dependency-version: 19.2.15
  dependency-type: direct:development
  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-23 04:34:17 +00:00
dependabot[bot]
7b4481b194
Bump aws-cdk-lib from 2.253.1 to 2.257.0 in /infra (#58)
Bumps [aws-cdk-lib](https://github.com/aws/aws-cdk/tree/HEAD/packages/aws-cdk-lib) from 2.253.1 to 2.257.0.
- [Release notes](https://github.com/aws/aws-cdk/releases)
- [Changelog](https://github.com/aws/aws-cdk/blob/main/CHANGELOG.v2.alpha.md)
- [Commits](https://github.com/aws/aws-cdk/commits/v2.257.0/packages/aws-cdk-lib)

---
updated-dependencies:
- dependency-name: aws-cdk-lib
  dependency-version: 2.257.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-23 04:34:11 +00:00
dependabot[bot]
91b9386293
Bump aws-cdk from 2.1122.0 to 2.1124.1 in /infra (#63)
Bumps [aws-cdk](https://github.com/aws/aws-cdk-cli/tree/HEAD/packages/aws-cdk) from 2.1122.0 to 2.1124.1.
- [Release notes](https://github.com/aws/aws-cdk-cli/releases)
- [Commits](https://github.com/aws/aws-cdk-cli/commits/aws-cdk@v2.1124.1/packages/aws-cdk)

---
updated-dependencies:
- dependency-name: aws-cdk
  dependency-version: 2.1124.1
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-23 04:34:07 +00:00
dependabot[bot]
121a1f2dae
Bump @types/react from 19.2.14 to 19.2.15 in /web (#60)
Bumps [@types/react](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/react) from 19.2.14 to 19.2.15.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/react)

---
updated-dependencies:
- dependency-name: "@types/react"
  dependency-version: 19.2.15
  dependency-type: direct:development
  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-23 04:34:05 +00:00
dependabot[bot]
9a6e0bfc44
Update boto3 requirement in /lambdas/library-ingest (#59)
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.10...1.43.14)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-23 04:33:59 +00:00
dependabot[bot]
46a60279f7
Update boto3 requirement in /lambdas/pdf-generate (#57)
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.10...1.43.14)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-23 04:33:56 +00:00
dependabot[bot]
ca77feada6
Bump react-native-safe-area-context from 5.7.0 to 5.8.0 in /mobile (#55)
Bumps [react-native-safe-area-context](https://github.com/AppAndFlow/react-native-safe-area-context) from 5.7.0 to 5.8.0.
- [Release notes](https://github.com/AppAndFlow/react-native-safe-area-context/releases)
- [Commits](https://github.com/AppAndFlow/react-native-safe-area-context/compare/v5.7.0...v5.8.0)

---
updated-dependencies:
- dependency-name: react-native-safe-area-context
  dependency-version: 5.8.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-23 04:33:50 +00:00
dependabot[bot]
c2627ae290
Bump @tanstack/react-query from 5.100.11 to 5.100.13 in /web (#53)
Bumps [@tanstack/react-query](https://github.com/TanStack/query/tree/HEAD/packages/react-query) from 5.100.11 to 5.100.13.
- [Release notes](https://github.com/TanStack/query/releases)
- [Changelog](https://github.com/TanStack/query/blob/main/packages/react-query/CHANGELOG.md)
- [Commits](https://github.com/TanStack/query/commits/@tanstack/react-query@5.100.13/packages/react-query)

---
updated-dependencies:
- dependency-name: "@tanstack/react-query"
  dependency-version: 5.100.13
  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-23 04:33:48 +00:00
dependabot[bot]
e75999b99d
Update boto3 requirement in /lambdas/suggestions (#54)
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.35.0...1.43.14)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-23 04:33:40 +00:00
dependabot[bot]
254c64d6e9
Update boto3 requirement in /lambdas/pdf-extract (#56)
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.10...1.43.14)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-23 04:33:33 +00:00
dependabot[bot]
79ec029a0b
Bump react-native-app-auth from 8.2.0 to 8.3.0 in /mobile (#52)
Bumps [react-native-app-auth](https://github.com/FormidableLabs/react-native-app-auth) from 8.2.0 to 8.3.0.
- [Release notes](https://github.com/FormidableLabs/react-native-app-auth/releases)
- [Commits](https://github.com/FormidableLabs/react-native-app-auth/compare/react-native-app-auth@8.2.0...react-native-app-auth@8.3.0)

---
updated-dependencies:
- dependency-name: react-native-app-auth
  dependency-version: 8.3.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-23 04:33:28 +00: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
a199b4675c
Merge pull request #50 from Sea-Haven-Industries/feature/fix-phase-2
Some checks failed
Deploy / Deploy to AWS (push) Waiting to run
Deploy Mobile (iOS) / Build & Upload to TestFlight (push) Has been cancelled
Fix Phase 2 audit findings: reliability, UX, and monitoring
2026-05-20 19:09:44 -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
dfbd0562ee
Merge pull request #48 from Sea-Haven-Industries/mobile/fix-react-version-and-ui
Fix React version, mobile auth, web/API bugs, and admin UX hardening
2026-05-20 18:29:15 -04:00
Adam Moussa
a978fdd292 Update retrospective with session 5: automated QA and 18-bug fix sweep
Documents the parallel 4-agent QA run (~145 test cases), the 18 bugs
found, and all fixes applied in the preceding 4 commits. Adds session 5
changelog and QA coverage summary table.
2026-05-20 18:10:02 -04:00
Adam Moussa
5e89e42e6a Extract shared constants and format utils, wire admin dashboard filters
Move STATUS_COLORS and PRIORITY_COLORS to constants/index.ts and
formatCurrency/formatDate/formatDateTime to lib/format.ts — previously
duplicated across 5 and 4 files respectively.

AdminDashboard: Wire Category and Priority filter dropdowns to
usePaginatedList extraParams (were no-op onChange handlers).

ProposalDetailPage: Add 'Revised' to STATUS_ORDER so the stepper
renders correctly for revised proposals.
2026-05-20 18:09:11 -04:00
Adam Moussa
4d72b63547 Add frontend role guards, fix dashboard data exposure, and harden UX
RoleGuard: New component wrapping admin routes — dispatchers navigating
to /admin/* by URL now redirect to / instead of seeing error states.

Dashboard: Add mine=true filter so dispatchers only see their own
proposals and stats, not all users' data.

AdminWorkspace: Auto-save dirty changes before approving so edits to
refined scope and line items aren't silently discarded.

ProposalFormPage: Add onError toast and 300ms debounce on customer
search (was firing an API call per keystroke).

admin.ts: Stop swallowing errors in getPdf — let them propagate to the
mutation's onError handler. Fix AuditEntry.details type to string|null.

LoginPage: Fix pre-existing TS error with noUncheckedIndexedAccess.
2026-05-20 18:09:04 -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
0b1af71166 Add retrospective covering mobile and web testing sessions
Documents findings from all four sessions (2026-05-18 through 2026-05-20):
mobile CI/CD, device testing, and web dev-mode testing. Includes
standards compliance audit, lessons learned, and prioritized follow-ups.
2026-05-20 17:30:48 -04:00