diff --git a/.gitignore b/.gitignore index d13735f9..6c2b14ec 100644 --- a/.gitignore +++ b/.gitignore @@ -61,3 +61,7 @@ context/ memory-bank/ workflows/ AI_CONTEXT.md +memory-bank/activeContext.md +memory-bank/change-log.md +memory-bank/refactor-plan-actions-index.md +memory-bank/progress.md diff --git a/memory-bank/activeContext.md b/memory-bank/activeContext.md deleted file mode 100644 index 189531a1..00000000 --- a/memory-bank/activeContext.md +++ /dev/null @@ -1,712 +0,0 @@ -# Active Context — PEDW FrontEnd - -## Current development focus (from recent commits) - -- API contract consistency rollout (TASK22102), starting with helper-based response normalization in selected email/admin handlers. -- TASK22109 email API contract parity and phase21 contract coverage expansion. -- Search/case navigation correctness, especially breadcrumb and back-link behavior. -- My Portal "view all" and DNS application path handling. -- Welsh/English email behavior for specific notification templates. -- PDF output formatting and hyperlink behavior. - -## TASK22109 completion status (2026-03-18) - -- Branch: `TASK22109-email-api-contracts` -- Commits: - - `6610e5c` — email API contract cleanup + initial phase21 email coverage - - `d17f3a1` — expanded email contract coverage and logging hygiene - - `e9cf1cf` — mini-slice tidy + notify negative-path tests -- Scope completed: - - email handler cleanup/hardening in: - - `pages/api/email/getevents.js` - - `pages/api/email/getdocuments.js` - - `pages/api/email/getall.js` - - `pages/api/email/getmailinglist.js` - - `pages/api/email/getcaseref.js` - - `pages/api/email/notify.js` - - expanded phase21 contract tests: - - `tests/phase21/email-handler-contract.test.cjs` - - `tests/phase21/api-contract-slice1.test.cjs` - - `tests/phase21/_shared.cjs` -- Validation snapshot: - - `node tests/phase21/api-contract-slice1.test.cjs` -> pass - - helper 4/4 - - file-handler 11/11 - - email-handler 12/12 - - `npm run lint` -> warnings only (pre-existing) - -## TASK22168 endpoint slice status (2026-03-19) - -- Branch: `TASK22168-endpoint-account-contract-consistency` -- Scope completed (next coherent low-risk `pages/api/endpoint/**` slice): - - `pages/api/endpoint/getaccounts_api.js` - - `pages/api/endpoint/getemailaccountcheck_api.js` - - `pages/api/endpoint/getpreferredlanguage_api.js` - - `tests/phase21/endpoint-handler-contract.test.cjs` - - `tests/phase21/api-contract-slice1.test.cjs` (runner extended) -- Pattern applied (aligned with TASK22109): - 1. removed dead/noisy code in selected handlers (unused imports + noisy/commented debug remnants), - 2. standardized structured negative-path envelopes for missing required input and catch/failure paths, - 3. preserved success response behavior (`data` pass-through), - 4. added focused phase21 endpoint contract tests: - - missing required input - - catch/failure path - - one success contract parity assertion. -- Validation snapshot: - - `node tests/phase21/api-contract-slice1.test.cjs` -> pass - - helper 4/4 - - file-handler 11/11 - - email-handler 12/12 - - endpoint-handler 7/7 - - `npm run lint` -> warnings only (pre-existing react-hooks warnings) - -- Risk/rollback snapshot: - - risk: broader endpoint touch in one bundle could drift contracts - - mitigation: success payloads preserved as upstream `data`; phase21 endpoint tests expanded to 18/18 - - rollback: revert `getlogin_api`, `getportallogin_api`, `getportalloginproxy_api`, `getpersonalaccount_api`, and phase21 endpoint test updates, then rerun phase21 + lint - -## Suggested next work package - -- Continue API contract consistency in `pages/api/endpoint/**` with the same pattern used in TASK22109: - 1. remove noisy logging/commented dead traces in selected endpoints, - 2. add/standardize structured negative-path responses where contract drift exists, - 3. add focused phase21 endpoint contract tests for missing required input + catch-path failures. - -## Recently changed areas (high signal) - -- `components/breadcrumbs.js` -- `components/case/summary.js` -- `components/search/searchresults.js` -- `components/search/addresssearchresults.js` -- `components/myportal/viewall.js` -- `pages/myportal/case/[ticketnumber].js` -- `pages/api/email/notify.js` -- `actions/index.js` -- `actions/core/env.js` -- `actions/core/logger.js` -- `actions/core/hash.js` -- `actions/core/token.js` -- `actions/core/headers.js` -- `actions/services/legacyActionsService.js` -- `i18n.js` - -## Active concerns - -- Breadcrumb and route-state logic is complex and query-dependent (`va`, `adv`, `ads`, `key`), so regressions are easy. -- Locale-specific route and label behavior is still a high-risk area due to rewrite + component logic coupling. -- Sensitive logging remains present in auth/email/actions paths and should be reduced/redacted over time. -- Hash validation on some file endpoints appears inconsistent (some checks active, some commented), requiring careful change discipline. - -## Refactor status update (2026-03-12) - -- Priority 1 refactor (Phase 1) is in place: - - `actions/index.js` now acts as a compatibility barrel. - - Core helper concerns were extracted into `actions/core/*`. - - Existing API/file/domain wrappers were moved into `actions/services/legacyActionsService.js` with backward-compatible exports retained via the barrel. -- No intentional behavior changes were introduced in this phase; focus was structural risk reduction. -- Priority 1 refactor (Phase 2) is now in place: - - Domain service grouping modules added under `actions/services/*`. - - `actions/services/index.js` now provides grouped service barrel exports. - - `actions/index.js` now re-exports from `./services` and `./core/*` while preserving existing public action names. -- `legacyActionsService` remains as a compatibility backing module and should be slimmed in later increments as consumers move to direct service imports. - -## Refactor status update (Priority 1 execution pass — 2026-03-12) - -- Completed an additional Priority 1 consumer-migration pass focused on high-use portal/form helpers. -- Updated these files to use focused service/core imports instead of broad `actions` barrel imports: - - `components/case/representation/representationElements.js` - - `components/elements/index.js` - - `components/utils/index.js` - - `lib/newappeal/loadNewAppealPage.js` - - `lib/myportal/loadMyPortalAppealPage.js` - - `components/myportal/topthree.js` - - `components/myportal/topthree_reps.js` - - `components/myportal/awaitingsubmissionfromblob.js` -- Compatibility model remains in place via `actions/index.js`; migration is incremental and non-breaking by design. - -## Refactor status update (Priority 1 execution pass — viewall/search/unsubscribe) - -- Completed another focused import migration pass to reduce broad `actions` barrel coupling in user-facing high-use areas: - - `components/myportal/viewall.js` - - `components/search/addresssearchresults.js` - - `pages/unsubscribe/[watchlistid].js` - - `pages/unsubscribeall/[watchlistid].js` -- These files now use explicit imports from `actions/services/*` and `actions/core/*` modules. -- Remaining non-comment broad `actions` imports are now primarily in selected `pages/api/endpoint/*` and `pages/api/file/*` handlers. - -## Refactor status update (Priority 1 execution pass — endpoint/file proxies) - -- Completed focused import migration for selected endpoint and file proxy handlers: - - `pages/api/endpoint/getmylpacases_api.js` - - `pages/api/endpoint/getbasicdnssearchpaged_api.js` - - `pages/api/endpoint/getsearchdocumentdetailspaged_api.js` - - `pages/api/endpoint/getbasicsearchpaged_api.js` - - `pages/api/file/getawaitingsubmissionfromblobproxy.js` - - `pages/api/file/getrepsblobproxy.js` - - `pages/api/file/getbloblistproxy.js` - - `pages/api/file/createappealcompletemessageproxy_api.js` -- Replaced broad `../../../actions` imports with focused `actions/core/*` and service-module imports. -- Eliminated duplicated local hash helper in `getmylpacases_api.js` by reusing shared `actions/core/hash`. -- Current broad-import scan indicates only comment-only legacy references remain. - -## Delivery handover status (2026-03-13) - -- Current import-migration wave has been checked in and completed through PR. -- This branch is now treated as the completed migration baseline. -- Next implementation chunk should start on a **new branch** and target decomposition of `actions/services/legacyActionsService.js`. -- Immediate focus for next branch: - 1. extract low-risk reference/search wrappers into direct service/client modules, - 2. migrate portal/document internals in small parity-checked batches, - 3. slim compatibility layer once parity is proven. - -## Phase 5 kickoff status (2026-03-13) - -- Branch in progress: `TASK21997-phase5-legacyactions-split`. -- First decomposition slice completed: - - search wrappers extracted to `actions/services/searchDirectService.js` - - reference-data wrappers extracted to `actions/services/referenceDataDirectService.js` - - `searchService` and `referenceDataService` now route through these direct modules. -- `legacyActionsService` remains in place for non-migrated domains (portal/document/account/case/admin/notify/integration) pending next slices. - -## Phase 5 status update (2026-03-13 — document slice) - -- Added `actions/services/documentDirectService.js` and migrated `documentService.js` to route through it. -- `legacyActionsService` now remains for: - - portal, account, case, admin, notify, integration domains. -- Search/reference/document grouped services now point at dedicated direct modules. - -## Phase 5 completion status (2026-03-13) - -- Grouped services now route through focused direct modules for all domains: - - search, reference-data, document, portal, account, case, admin, integration, notify. -- `actions/services/legacyActionsService.js` has been removed. -- Current architecture baseline: - - `actions/index.js` -> compatibility barrel re-exporting `actions/services` + core modules - - `actions/services/*Service.js` -> grouped public service boundaries - - `actions/services/*DirectService.js` -> implementation modules per domain -- Validation checkpoints completed: - - zero `legacyActionsService` imports in `actions/services/*.js` - - lint passes with warnings only - - build succeeds - -## Phase 6 hardening status (2026-03-13 — in progress) - -- Working branch: `TASK21998-phase6-postphase5-hardening` (created from `SIPS-Development`). -- Main hardening actions completed so far: - - Added focused parity test harness: - - `tests/phase6/service-parity.test.cjs` - - verifies grouped service import/export parity and `actions/services/index.js` re-export stability. - - Added shared error-path helper: - - `actions/services/httpServiceUtils.js` - - consolidates repeated `consoleLogger + error.response` and `ErrResponse` generation patterns. - - Applied safe duplication reduction in: - - `searchDirectService.js` - - `referenceDataDirectService.js` - - `caseDirectService.js` - - `adminDirectService.js` - - Logging cleanup for sensitive/noisy service paths (removed debug `console.log` usage) in: - - `searchDirectService.js` - - `documentDirectService.js` - - `portalDirectService.js` - - `caseDirectService.js` - - `adminDirectService.js` - -### Current validation evidence - -- `node tests/phase6/service-parity.test.cjs` -> pass -- `node tests/phase6/service-behaviour.test.cjs` -> pass (8/8) -- `npm run lint` -> warnings only -- Targeted local smoke snapshots: - - `GET /advancedsearch` and `GET /cy/advancedsearch` -> 200 - - `GET /case` and `GET /cy/case` -> 200 - - `GET /myportal` and `GET /cy/myportal` -> 307 redirect to `/auth/signin` (unauthenticated negative path) - - `GET /api/file/getbloblistproxy?container=test&casefolderID=test` -> 400 (negative path) - - `POST /api/email/notify` with empty payload -> 400 (negative path) - -### Active caveat - -- `GET /searchresults` and `GET /cy/searchresults` return 500 in current local dev run due pre-existing SSR serialization issue: - - `initialState.search.searchString` is undefined in `getServerSideProps` payload. - - captured in `/tmp/phase6-dev.log`. - -## Phase 7 hardening status (2026-03-13) - -- Working branch created from `origin/SIPS-Development`: - - `TASK21988a-phase7-postphase6-hardening` -- Pre-existing search results SSR serialization issue now addressed: - - `pages/searchresults.js` - - changed `setSearch(query.q)` to `setSearch(query?.q || "")` in `getServerSideProps`. - - local smoke result: both `/searchresults` and `/cy/searchresults` return 200 in this run. -- Behavioural test expansion delivered for remaining service domains: - - `tests/phase7/service-behaviour.test.cjs` - - covers document, portal, account, notify, integration. - -### Phase 7 validation evidence snapshot - -- `node tests/phase6/service-parity.test.cjs` -> pass -- `node tests/phase6/service-behaviour.test.cjs` -> pass (8/8) -- `node tests/phase7/service-behaviour.test.cjs` -> pass (10/10) -- `npm run lint` -> warnings only (existing react-hooks dependency warnings; no new lint errors) - -### Phase 7 smoke/negative-path snapshot - -- Dev server auto-bound to `localhost:3001` (3000 already in use). -- `GET /searchresults`, `GET /cy/searchresults` -> 200 -- `GET /case`, `GET /cy/case` -> 200 -- `GET /myportal`, `GET /cy/myportal` -> 307 redirect to `/auth/signin` -- `GET /api/file/getbloblistproxy?container=test&casefolderID=test` -> 400 -- `POST /api/email/notify` with `{}` -> 400 - -### Testing strategy decision (captured) - -- Current phase includes **both**: - 1. migration/parity guard tests, - 2. focused behavioural unit tests for critical response/error contracts. -- Broader behavioural coverage remains a follow-on expansion item after this focused baseline. - -## Phase 8 hardening status (2026-03-13) - -- Working branch created from `origin/SIPS-Development`: - - `TASK22017-phase8-hardening-slice` -- Sensitive API hardening slice completed across: - - `pages/api/file/deleteblobcase.js` - - `pages/api/file/deleteblobrep.js` - - `pages/api/file/createappealcompletemessage_api.js` - - `pages/api/endpoint/getportallogin_api.js` -- Hash/integrity posture updates: - - re-enabled hash validation on previously bypassed/commented file handlers - - added standardized early 400 handling for missing/invalid hash and missing key params - - preserved response-shape contracts and function signatures -- Logging discipline updates: - - removed noisy direct `console.log` usage in `createappealcompletemessage_api` - - routed error paths through `consoleLogger` in updated sensitive flow -- Required consumer parity updates applied: - - `actions/services/documentDirectService.js` - - now appends hash for `deleteblobcase` and `deleteblobrep` calls - - `actions/services/portalDirectService.js` - - now appends hash for `createappealcompletemessage_api` call using existing hash path contract - -### Phase 8 validation evidence snapshot - -- `node tests/phase6/service-parity.test.cjs` -> pass -- `node tests/phase6/service-behaviour.test.cjs` -> pass (8/8) -- `node tests/phase7/service-behaviour.test.cjs` -> pass (10/10) -- `node tests/phase8/service-behaviour.test.cjs` -> pass (5/5) -- `npm run lint` -> warnings only (pre-existing hook dependency warnings) - -### Phase 8 manual HTTP snapshot - -- Dev server on `http://localhost:3001`. -- Negative-path checks for invalid/missing hash (and missing required params where relevant) return **400** across all 4 target handlers. -- Valid-hash spot-check for `getportallogin_api` reached hash-validated path but still returned **400** due local upstream relay/CRM dependency behavior. - -## Phase 9 hardening status (2026-03-13) - -- Working branch created from `origin/SIPS-Development`: - - `TASK22019-phase-9-hardening` -- Additional sensitive API hardening slice completed across: - - `pages/api/file/createrepcompletemessage_api.js` - - `pages/api/file/upload.js` - - `pages/api/file/uploadsinglefile.js` - - `pages/api/file/setupcontainer.js` -- Hash/integrity posture updates: - - re-enabled/enforced hash checks in handlers where hash validation was bypassed/commented - - standardized early 400 handling for missing/invalid hash and missing key query/body values - - preserved response-shape contracts and function signatures -- Logging discipline updates: - - removed noisy `console.log` traces from sensitive upload/rep-complete message paths - - retained centralized error logging via `consoleLogger` where present -- Required caller parity updates applied: - - `actions/services/portalDirectService.js` - - `sendRepCompleteMessage` now appends hash - - `actions/services/documentDirectService.js` - - `uploadFiles`, `uploadRepFiles`, `uploadSingleFile` now append hash - -### Phase 9 validation evidence snapshot - -- `node tests/phase6/service-parity.test.cjs` -> pass -- `node tests/phase6/service-behaviour.test.cjs` -> pass (8/8) -- `node tests/phase7/service-behaviour.test.cjs` -> pass (10/10) -- `node tests/phase8/service-behaviour.test.cjs` -> pass (5/5) -- `node tests/phase9/service-behaviour.test.cjs` -> pass (5/5) -- `npm run lint` -> warnings only (pre-existing hook dependency warnings) - -### Phase 9 manual HTTP snapshot - -- Negative-path checks for missing/invalid hash and invalid/missing key params on all 4 phase-9 handlers return **400** on local server (`localhost:3000`). -- Valid-hash happy-path spot-check completed using `.env.local` hash key: - - `POST /api/file/uploadsinglefile?hash=` -> **200** - -## Phase 10 hardening status (2026-03-13) - -- Continued on branch: - - `TASK22019-phase-9-hardening` -- Additional sensitive API hardening slice completed across: - - `pages/api/file/getawaitingsubmissionfromblob.js` - - `pages/api/file/getprogressobjblob.js` - - `pages/api/file/getbloblist.js` - - `pages/api/file/getrepsblob.js` -- Hash/integrity posture updates: - - explicit early 400 guards for missing/empty required query inputs and hash - - standardized early hash-mismatch 400 behaviour in all 4 handlers - - preserved response-shape contracts and function signatures -- Logging discipline updates: - - removed old commented debug traces in touched handlers -- Caller parity: - - no additional service-layer updates required in this slice; existing direct services already append hash for these APIs. - -### Phase 10 validation evidence snapshot - -- `node tests/phase6/service-parity.test.cjs` -> pass -- `node tests/phase6/service-behaviour.test.cjs` -> pass (8/8) -- `node tests/phase7/service-behaviour.test.cjs` -> pass (10/10) -- `node tests/phase8/service-behaviour.test.cjs` -> pass (5/5) -- `node tests/phase9/service-behaviour.test.cjs` -> pass (5/5) -- `node tests/phase10/service-behaviour.test.cjs` -> pass (5/5) -- `npm run lint` -> warnings only (pre-existing hook dependency warnings) - -### Phase 10 manual HTTP snapshot - -- Missing-hash negative-path checks for all 4 handlers return **400** (`localhost:3000`). -- Valid-hash spot-check result: - - `getbloblist` returned **500** with valid hash in local environment (consistent with downstream/local dependency constraints; hash gate passed). - -## Phase 11 hardening status (2026-03-13) - -- Continued on branch: - - `TASK22019-phase-9-hardening` -- Additional sensitive API hardening slice completed across: - - `pages/api/file/getbloblist.js` - - `pages/api/file/deleteblob.js` - - `pages/api/file/deleteawaitingsubmissionfromblob.js` -- Hash/integrity posture updates: - - explicit early 400 guards for missing/empty required query inputs and hash - - standardized early hash-mismatch 400 behaviour in all touched handlers - - preserved response-shape contracts and function signatures -- Logging discipline updates: - - removed old commented debug traces in touched handlers -- Caller parity: - - no additional service-layer updates required in this slice. - -### Phase 11 validation evidence snapshot - -- `node tests/phase6/service-parity.test.cjs` -> pass -- `node tests/phase6/service-behaviour.test.cjs` -> pass (8/8) -- `node tests/phase7/service-behaviour.test.cjs` -> pass (10/10) -- `node tests/phase8/service-behaviour.test.cjs` -> pass (5/5) -- `node tests/phase9/service-behaviour.test.cjs` -> pass (5/5) -- `node tests/phase10/service-behaviour.test.cjs` -> pass (5/5) -- `node tests/phase11/service-behaviour.test.cjs` -> pass (4/4) -- `npm run lint` -> warnings only (pre-existing hook dependency warnings) - -### Phase 11 manual HTTP snapshot - -- Missing/invalid-hash negative-path checks for selected handlers return **400** (`localhost:3000`). -- Valid-hash spot-check result: - - `getbloblist` returned **500** with valid hash in local environment (consistent with downstream/local dependency constraints; hash gate passed). - -## Phase 12 hardening status (2026-03-13) - -- Continued on branch: - - `TASK22019-phase-9-hardening` -- Additional sensitive API hardening slice completed across: - - `pages/api/file/downloadblob.js` - - `pages/api/file/getbloblistproxy.js` - - `pages/api/file/getrepsblobproxy.js` - - `pages/api/file/getawaitingsubmissionfromblobproxy.js` -- Hash/integrity posture updates: - - explicit early 400 guards for missing/empty required query inputs - - standardized early hash-mismatch 400 behaviour in `downloadblob` - - preserved response-shape contracts and function signatures - -### Phase 12 validation evidence snapshot - -- `node tests/phase6/service-parity.test.cjs` -> pass -- `node tests/phase6/service-behaviour.test.cjs` -> pass (8/8) -- `node tests/phase7/service-behaviour.test.cjs` -> pass (10/10) -- `node tests/phase8/service-behaviour.test.cjs` -> pass (5/5) -- `node tests/phase9/service-behaviour.test.cjs` -> pass (5/5) -- `node tests/phase10/service-behaviour.test.cjs` -> pass (5/5) -- `node tests/phase11/service-behaviour.test.cjs` -> pass (4/4) -- `node tests/phase12/service-behaviour.test.cjs` -> pass (4/4) -- `npm run lint` -> warnings only (pre-existing hook dependency warnings) - -### Phase 12 manual HTTP snapshot - -- Missing/invalid-input negative-path checks for selected handlers return **400** (`localhost:3000`). -- Valid-hash spot-check result: - - `downloadblob` returned **500** with valid hash in local environment (consistent with downstream/local dependency constraints; hash gate passed). - -## Phase 13 hardening status (2026-03-13) - -- Continued on branch: - - `TASK22019-phase-9-hardening` -- Additional sensitive API hardening slice completed across: - - `pages/api/file/deleteblobcase.js` - - `pages/api/file/deleteblobrep.js` - - `pages/api/file/createcaseinvolvement_api.js` - - `pages/api/file/createrepinvolvement_api.js` -- Hash/integrity posture updates: - - explicit early 400 guards for missing/empty required query/body inputs - - standardized early hash-mismatch 400 behaviour in delete-blob handlers - - preserved response-shape contracts and function signatures -- Logging discipline updates: - - removed noisy direct body/query logging from involvement handlers - -### Phase 13 validation evidence snapshot - -- `node tests/phase6/service-parity.test.cjs` -> pass -- `node tests/phase6/service-behaviour.test.cjs` -> pass (8/8) -- `node tests/phase7/service-behaviour.test.cjs` -> pass (10/10) -- `node tests/phase8/service-behaviour.test.cjs` -> pass (5/5) -- `node tests/phase9/service-behaviour.test.cjs` -> pass (5/5) -- `node tests/phase10/service-behaviour.test.cjs` -> pass (5/5) -- `node tests/phase11/service-behaviour.test.cjs` -> pass (4/4) -- `node tests/phase12/service-behaviour.test.cjs` -> pass (4/4) -- `node tests/phase13/service-behaviour.test.cjs` -> pass (7/7) -- `npm run lint` -> warnings only (pre-existing hook dependency warnings) - -### Phase 13 manual HTTP snapshot - -- Missing/invalid-input negative-path checks for selected handlers return **400** (`localhost:3000`). -- Valid-hash spot-check result: - - `deleteblobcase` returned **500** with valid hash in local environment (consistent with downstream/local dependency constraints; hash gate passed). - -## Phase 14 hardening status (2026-03-13) - -- Continued on branch: - - `TASK22019-phase-9-hardening` -- Addressed browser runtime error in authenticated new-appeal journey: - - `TypeError` in `hashAPIPath` caused by client-side code attempting to parse server-only `HASHKEY`. -- Implemented server-side hash signing bridge for browser callers: - - new endpoint `pages/api/endpoint/gethash_api.js` - - session-gated (`getSession`), allow-listed supported API prefixes, returns `{ hash }`. -- Updated direct service callers to use signer endpoint instead of direct client hash computation: - - `actions/services/documentDirectService.js` - - `actions/services/portalDirectService.js` -- Maintained contract compatibility for target file APIs and existing response shapes. - -### Phase 14 validation evidence snapshot - -- phase6 parity/behaviour tests -> pass -- phase7/8/9/10/11/12/13 behaviour tests -> pass -- phase14 behaviour tests -> pass (4/4) -- lint -> warnings only (pre-existing hook dependency warnings) - -## Phase 14 closeout follow-up status (2026-03-13) - -- Continued on branch: - - `TASK22019-phase-9-hardening` -- Browser-safe hash signing expanded for portal login flow: - - `actions/services/accountDirectService.js` - - `getPortalLogin` now requests signed hash from `/api/endpoint/gethash_api` - - server fallback retained for non-browser contexts when `HASHKEY` is present - - `pages/api/endpoint/gethash_api.js` - - allow-list now includes `/api/endpoint/getportallogin_api` -- Contract alignment + runtime fix updates: - - `pages/api/file/getrepsblob.js` - - removed hard requirement for `casefolderID` to match actual route contract (`container + hash`) - - `components/elements/index.js` - - restored missing `updateLinks` import required by Quill-related runtime path - -### Follow-up validation evidence - -- `node tests/phase7/service-behaviour.test.cjs` -> pass (10/10) -- `node tests/phase14/service-behaviour.test.cjs` -> pass (5/5) -- `node tests/phase9/service-behaviour.test.cjs` -> pass (5/5) -- full previously-run phase6–phase14 suite remains passing -- `npm run lint` -> warnings only (pre-existing `react-hooks/exhaustive-deps` set) - -### Active risk posture after follow-up - -- Signer endpoint scope remains controlled by strict allow-list (single new path added). -- Response-shape contract stability preserved for touched handlers/services. -- Remaining risk is primarily external dependency behavior on valid-hash happy paths in local environments (relay/storage), not hash-bypass behavior. - -## Phase 15 hardening status (2026-03-13) - -- Working branch created from `origin/SIPS-Development`: - - `TASK22028-phase15-hardening-slice` -- Delivered consistency-only hardening across 4 additional sensitive file handlers: - - `pages/api/file/upload.js` - - `pages/api/file/uploadsinglefile.js` - - `pages/api/file/createappealcompletemessage_api.js` - - `pages/api/file/setupcontainer.js` -- Hardening posture updates: - - standardized explicit early 400 on missing hash where validation was already required - - standardized early hash-mismatch return path style in `setupcontainer` - - preserved response-shape/signature contracts (no intended contract changes) -- Added focused phase-15 tests: - - `tests/phase15/service-behaviour.test.cjs` - - negative-path checks for missing/invalid hash across all selected handlers - - required-input negative-path checks where applicable - - one valid-hash mocked happy-path check (`setupcontainer` response shape) - -### Phase 15 validation evidence snapshot - -- `node tests/phase6/service-parity.test.cjs` -> pass -- `node tests/phase6/service-behaviour.test.cjs` -> pass (8/8) -- `node tests/phase7/service-behaviour.test.cjs` -> pass (10/10) -- `node tests/phase8/service-behaviour.test.cjs` -> pass (5/5) -- `node tests/phase9/service-behaviour.test.cjs` -> pass (5/5) -- `node tests/phase10/service-behaviour.test.cjs` -> pass (5/5) -- `node tests/phase11/service-behaviour.test.cjs` -> pass (4/4) -- `node tests/phase12/service-behaviour.test.cjs` -> pass (4/4) -- `node tests/phase13/service-behaviour.test.cjs` -> pass (7/7) -- `node tests/phase14/service-behaviour.test.cjs` -> pass (5/5) -- `node tests/phase15/service-behaviour.test.cjs` -> pass (5/5) -- `npm run lint` -> warnings only (pre-existing `react-hooks/exhaustive-deps` warnings) - -### Phase 15 manual HTTP snapshot - -- Dev server run on `http://localhost:3002`. -- Missing/invalid hash negative-path checks for selected handlers -> **400**. -- Missing required params where applicable -> **400**. -- Valid-hash spot-check: - - `GET /api/file/setupcontainer?ident=c1&hash=` -> **200**. - -## Phase 16 hardening status (2026-03-13) - -- Continued on branch: - - `TASK22028-phase15-hardening-slice` -- Added a consistency-only file-proxy hardening slice across: - - `pages/api/file/getbloblistproxy.js` - - `pages/api/file/getrepsblobproxy.js` - - `pages/api/file/getawaitingsubmissionfromblobproxy.js` -- Changes focused on: - - standardized required-input guards via `hasValue` - - removed unused imports/dead constants from touched proxy handlers - - preserved existing response contracts and status semantics -- Added focused test pack: - - `tests/phase16/service-behaviour.test.cjs` - -### Phase 16 validation evidence snapshot - -- phase6 parity + phase6–phase15 behavioural suites: pass -- phase16 behavioural suite: pass (4/4) -- lint: warnings only (pre-existing) - -## Follow-up status (2026-03-13) - -- Applied targeted signer allow-list fix for browser delete-awaiting-submission path. -- Updated `pages/api/endpoint/gethash_api.js` allow-list with: - - `/api/file/deleteblobcase` -- Added focused behavioural test: - - `tests/phase14/service-behaviour.test.cjs` now includes allow-list coverage for deleteblobcase path. - -## Follow-up status (2026-03-13 — additional delete flows) - -- Expanded signer allow-list for additional browser delete paths: - - `/api/endpoint/deletemyrepresentations_api` - - `/api/endpoint/deletewatchedcases_api` - - `/api/file/deleteblobrep` -- Migrated affected direct-service delete calls to signer-based hash retrieval: - - `portalDirectService.deleteWatchedCases` - - `portalDirectService.deleteMyRepresentations` - - `documentDirectService.deleteAwaitingSubmissionsFromBlob` - - `documentDirectService.deleteMyRepresentationsFromBlob` - -## Follow-up status (2026-03-13 — myportal + i18n alignment) - -- Updated myportal representation delete call sites to pass `caseRef`: - - `components/myportal/topthree_reps.js` - - `components/myportal/viewall.js` -- Applied small view-all presentation cleanup and watched-case refresh filtering adjustment. -- Added missing `myportal` namespace mapping in `i18n.js` for `/newappeal/[appealtypes]`. - -## Phase 17 closeout status (2026-03-13) - -- Working branch created from `origin/SIPS-Development`: - - `TASK22057-phase17-hardening-closeout` -- Completed remaining closeout hardening slice for sensitive file handlers: - - `pages/api/file/generatepdf.js` - - `pages/api/file/generateappealpdf.js` - - `pages/api/file/createappealcompletemessageproxy_api.js` -- Applied consistency-only updates: - - standardized missing/invalid hash 400 negative paths in selected PDF handlers - - standardized required-input 400 guards where route contract requires it - - removed noisy direct logs from touched sensitive handlers - - preserved existing response shapes/signatures -- Added focused behavioural coverage: - - `tests/phase17/service-behaviour.test.cjs` (6/6 passing) - - includes missing/invalid hash negative-path checks and valid-input proxy happy-path contract check -- Broader consistency scan note: - - no additional broad hash/400 consistency gaps were identified in `pages/api/endpoint/**` in this pass. - -## Phase 18 additional consolidation slices (2026-03-14) - -- Continued on branch: - - `TASK22057-phase17-hardening-closeout` -- Completed all three requested additional slices: - 1. endpoint logging/input hygiene - 2. file hash-guard flow consistency - 3. create/update input-guard + logging hygiene -- Touched handlers: - - `pages/api/endpoint/deletewatchedcases_api.js` - - `pages/api/endpoint/getaccounts_api.js` - - `pages/api/endpoint/getbasicsearchpaged_api.js` - - `pages/api/endpoint/getappealpdfdocuments_api.js` - - `pages/api/file/deleteblob.js` - - `pages/api/file/deleteawaitingsubmissionfromblob.js` - - `pages/api/file/getprogressobjblob.js` - - `pages/api/file/getbloblist.js` - - `pages/api/file/createcase_api.js` - - `pages/api/file/updatecase_api.js` - - `pages/api/file/editRepJson.js` -- Outcome: - - consistent early 400 guard behavior for missing/invalid required inputs/hash in selected handlers - - noisy direct logs removed in touched sensitive flows - - no response-shape/signature contract changes intended -- Added focused test pack: - - `tests/phase18/service-behaviour.test.cjs` (8/8 pass) - -## Phase 19 endpoint consistency slice (2026-03-14) - -- Continued on branch: - - `TASK22057-phase17-hardening-closeout` -- Applied a small consistency-only slice across: - - `pages/api/endpoint/createwatchedcases_api.js` - - `pages/api/endpoint/getappealtypes_api.js` - - `pages/api/endpoint/getdnslist_api.js` -- Scope: - - standardized missing/malformed required `@odata.bind` handling in `createwatchedcases_api` with early 400 - - removed noisy query logging in appeal-types and dns-list endpoint handlers - - preserved response shapes/signatures -- Added focused test file: - - `tests/phase19/service-behaviour.test.cjs` (5/5 pass) - -## Phase 20 endpoint consistency slice (2026-03-14) - -- Continued on branch: - - `TASK22057-phase17-hardening-closeout` -- Applied a small consistency-only slice across: - - `pages/api/endpoint/getbasicdnssearch_api.js` - - `pages/api/endpoint/getbasicdnsurlsearch_api.js` - - `pages/api/endpoint/getbasicsearchdetailspaged_api.js` -- Scope: - - removed noisy query logging in `getbasicdnssearch_api` - - added early 400 for missing/empty `searchString` in `getbasicdnsurlsearch_api` - - added early 400 for missing required params in `getbasicsearchdetailspaged_api` - - preserved response shapes/signatures -- Added focused test file: - - `tests/phase20/service-behaviour.test.cjs` (5/5 pass) - -## Likely next steps - -1. Stabilize and simplify breadcrumb/back-link decision logic with focused regression checks. -2. Standardize hash-check enforcement patterns across file and endpoint APIs. -3. Reduce verbose logging in sensitive flows (auth/email/file/account). -4. Expand automated tests for navigation and representation eligibility edge-cases (currently minimal `tests/`). - -See `memory-bank/refactor-backlog.md` for the prioritized refactor plan and sequencing. -Priority 1 detailed execution plan is documented in `memory-bank/refactor-plan-actions-index.md`. - -## Areas currently important for contributors - -- `components/breadcrumbs.js` -- `components/case/summary.js` -- `pages/api/endpoint/**` -- `pages/api/file/**` -- `pages/api/auth/[...nextauth].js` -- `pages/api/email/notify.js` -- `next.config.js`, `i18n.js`, `locales/**` diff --git a/memory-bank/change-log.md b/memory-bank/change-log.md deleted file mode 100644 index 46e0fdf7..00000000 --- a/memory-bank/change-log.md +++ /dev/null @@ -1,1653 +0,0 @@ -# Change Log (AI/Human Curated) - -## Entry Template - -``` -date: YYYY-MM-DD -author: -scope: -type: change -rationale: -impact: -status: completed|rolled-back|partial - -Summary: -Validation: -Follow-ups: -``` - ---- - -### CL-001: Initial AI Enablement Bundle - -date: 2026-03-11 -author: Cline -scope: `.clinerules`, `ai-prompts/`, `context/`, `memory-bank/` -type: change -rationale: Establish consistent AI collaboration, delivery guardrails, and durable project context. -impact: Higher consistency/safety in future changes, especially around auth/i18n/public-service reliability. -status: completed - -Summary: -Created repository-specific governance, prompt templates, context documentation, and memory protocols with seed entries. - -Validation: - -- File structure and contents created in-repo. -- Content aligned to detected stack and key paths (`next-auth`, Prisma, middleware, i18n rewrites, Redux HYDRATE/persist). - -Follow-ups: - -- Confirm owner assignments for open questions. -- Add automation checks to enforce key guardrails over time. - ---- - -### CL-002: Priority 1 Refactor (Phase 1) — `actions/index.js` split foundation - -date: 2026-03-12 -author: Cline -scope: `actions/index.js`, `actions/core/*`, `actions/services/legacyActionsService.js`, `actions/clients/README.md`, `memory-bank/*` -type: change -rationale: Reduce coupling in the actions monolith by extracting core helpers while keeping backward-compatible exports for existing consumers. -impact: Lower regression blast radius for future actions-related changes; no intended functional behavior change. -status: completed - -Summary: -Extracted helper concerns from `actions/index.js` into focused `actions/core` modules (`env`, `logger`, `hash`, `token`, `headers`). Replaced `actions/index.js` with a compatibility barrel and moved operational wrappers into `actions/services/legacyActionsService.js` with imports from core helpers. - -Validation: - -- Branch created: `0000-update-actions-monolith`. -- Compatibility preserved by re-exporting legacy service functions plus core exports from `actions/index.js`. -- Lint run for regression check. - -Follow-ups: - -- Phase 2: split `legacyActionsService` by domain into dedicated service/client modules. -- Add helper-focused automated tests for core modules and export parity checks. - ---- - -### CL-003: Priority 1 Refactor (Phase 2) — service grouping via compatibility layer - -date: 2026-03-12 -author: Cline -scope: `actions/services/*`, `actions/index.js`, `memory-bank/*` -type: change -rationale: Continue reducing monolith risk by introducing domain service boundaries while preserving public action exports. -impact: Maintains backward compatibility for existing `../actions` imports; improves maintainability and safer future migration to targeted imports. -status: completed - -Summary: -Added grouped service modules (`searchService`, `caseService`, `accountService`, `portalService`, `documentService`, `referenceDataService`, `notifyService`, `adminService`, `integrationService`) plus `actions/services/index.js` barrel. Updated `actions/index.js` to export from `./services` (and core modules), keeping legacy function names/signatures available. - -Validation: - -- Service export coverage check confirms all legacy exports are represented in grouped services. -- `npm run lint` still fails due legacy Next/ESLint option incompatibility (tooling issue, unchanged by this refactor). - -Follow-ups: - -- Incrementally migrate high-churn consumers to direct service imports. -- Add automated export-parity and helper unit tests. - ---- - -### CL-004: Priority 1 Refactor (Phase 3) — targeted consumer import migration - -date: 2026-03-12 -author: Cline -scope: `components/case/summary.js`, `pages/api/email/notify.js`, selected `pages/api/endpoint/*`, `memory-bank/*` -type: change -rationale: Begin replacing broad `actions` barrel imports with focused service/core module imports in high-churn and representative endpoint areas. -impact: Lower coupling to monolithic action entrypoint while preserving behavior and public compatibility. -status: completed - -Summary: -Migrated targeted consumers to direct imports from `actions/services/*` and `actions/core/*` without changing function signatures or route contracts. - -Validation: - -- Lint still blocked by repository ESLint/Next option compatibility issue (pre-existing tooling configuration). -- Manual testing remains required for search/case/myportal/auth/notify/file matrix. - -Follow-ups: - -- Continue phased import migration for additional `pages/api/endpoint/**` handlers. -- Add export-parity and helper-level tests as planned. - ---- - -### CL-005: Priority 1 Refactor (Phase 4) — helper hardening + redacted logging baseline - -date: 2026-03-12 -author: Cline -scope: `actions/core/{guards,logger}.js`, `actions/index.js`, selected API handlers -type: change -rationale: Introduce low-risk guard and redaction primitives, then apply them to sensitive/high-churn API paths to reduce injection/privacy risk while preserving behavior. -impact: Better input hygiene and safer diagnostics in selected notify/login/contact flows; no intended contract changes. -status: completed - -Summary: -Added `guards` helper module (`isNonEmptyString`, `sanitizeString`, `escapeODataString`) and logger redaction utility (`redactSensitive`). Adopted these helpers in `notify`, `getpreferredlanguage_api`, and `createcrmtask_api` handlers. - -Validation: - -- `npm run lint` remains blocked by existing Next/ESLint options incompatibility in repository tooling. -- Targeted diff review confirms changes are scoped to helper hardening and selected handlers. - -Follow-ups: - -- Continue Phase 4 adoption for additional sensitive file/email/auth handlers. -- Add focused unit tests for `guards` and `redactSensitive` behavior. - ---- - -### CL-006: Priority 1 Refactor — consumer migration pass (portal/form/admin utilities) - -date: 2026-03-12 -author: Cline -scope: `components/admin/*`, `components/case/*`, `components/myportal/*`, `components/elements/index.js`, `components/utils/index.js`, `lib/*`, `memory-bank/*` -type: change -rationale: Continue Phase 3-style decoupling by replacing broad `actions` barrel imports with focused service/core imports in high-use consumer files while preserving behavior. -impact: Lower coupling to monolithic action barrel and clearer dependency boundaries; no intended functional behavior change. -status: completed - -Summary: -Migrated a targeted set of portal/form/admin utility consumers from `../../actions`/`../../../actions` to explicit imports from `actions/services/*` and `actions/core/*`. Also resolved migration-side compile issues in `components/myportal/topthree_reps.js` (duplicate import source and invalid `res.status` usage in client context). - -Validation: - -- In-scope consumer files now have no broad `from "../../actions"` / `from "../../../actions"` imports. -- `npm run lint` re-run; result unchanged and blocked by pre-existing Next/ESLint option incompatibility. - -Follow-ups: - -- Continue migrating remaining broad `actions` imports in `components/myportal/viewall.js`, `components/search/addresssearchresults.js`, unsubscribe flows, and selected API endpoints. -- Add focused manual smoke checks for myportal representations and awaiting-submission deletion/edit flows after this import migration. - ---- - -### CL-007: Priority 1 Refactor — consumer migration pass (viewall/search/unsubscribe) - -date: 2026-03-12 -author: Cline -scope: `components/myportal/viewall.js`, `components/search/addresssearchresults.js`, `pages/unsubscribe/[watchlistid].js`, `pages/unsubscribeall/[watchlistid].js`, `memory-bank/*` -type: change -rationale: Continue Phase 3 decoupling by removing additional broad `actions` barrel imports in high-use myportal/search/unsubscribe flows and replacing them with focused service/core imports. -impact: Reduced coupling to monolithic action barrel with intended behavior parity; no API contract changes intended. -status: completed - -Summary: -Migrated four additional consumers away from `../../actions`: - -- `components/myportal/viewall.js` -> `actions/services/documentService`, `actions/services/portalService`, `actions/core/logger` -- `components/search/addresssearchresults.js` -> `actions/services/portalService` -- `pages/unsubscribe/[watchlistid].js` -> `actions/core/{hash,token,headers,logger}` -- `pages/unsubscribeall/[watchlistid].js` -> `actions/core/{hash,token,headers,logger}` - -Validation: - -- Regex verification confirms these four files no longer import from the broad `actions` barrel. -- Repository-wide broad-import scan now reports 11 matches total, including comment-only occurrences and remaining endpoint/file handlers pending migration. - -Follow-ups: - -- Migrate remaining non-comment broad imports in selected `pages/api/endpoint/*` and `pages/api/file/*` handlers. -- Run focused manual smoke checks for myportal view-all watch/unwatch + unsubscribe routes (EN/CY path sanity and negative paths). - ---- - -### CL-008: Priority 1 Refactor — endpoint/file proxy import migration chunk - -date: 2026-03-12 -author: Cline -scope: `pages/api/endpoint/*`, `pages/api/file/*` (selected handlers), `memory-bank/*` -type: change -rationale: Continue Phase 3 migration by replacing broad `actions` barrel imports in selected endpoint/file proxy handlers with focused `actions/core/*` and service module imports. -impact: Further reduces monolithic import coupling in API paths while preserving existing request/response behavior and hash/token/header patterns. -status: completed - -Summary: -Migrated these handlers away from broad `../../../actions` imports: - -- `pages/api/endpoint/getmylpacases_api.js` - - `getLPA` -> `actions/services/referenceDataService` - - `azureHeaders`, `consoleLogger`, `getToken`, `hashAPIPath` -> `actions/core/*` - - removed local duplicated `hashAPIPath` implementation -- `pages/api/endpoint/getbasicdnssearchpaged_api.js` -- `pages/api/endpoint/getsearchdocumentdetailspaged_api.js` -- `pages/api/endpoint/getbasicsearchpaged_api.js` -- `pages/api/file/getawaitingsubmissionfromblobproxy.js` -- `pages/api/file/getrepsblobproxy.js` -- `pages/api/file/getbloblistproxy.js` -- `pages/api/file/createappealcompletemessageproxy_api.js` - -Validation: - -- Regex scans over `pages/api/endpoint` and `pages/api/file` show **0** remaining broad `from "../../../actions"` imports. -- `git status --short` confirms this chunk is isolated to the targeted endpoint/file handlers. - -Follow-ups: - -- Run focused manual smoke checks for touched endpoint/file flows (paged search APIs, LPA case retrieval, blob proxy endpoints). -- Continue hardening pass for sensitive handlers with guard/redaction helpers where not yet applied. - ---- - -### CL-009: Priority 1 import-migration wave checked in + PR completed; handover to next branch - -date: 2026-03-13 -author: Cline -scope: `actions/services/*` consumer and endpoint migrations (completed), planning handover docs -type: change -rationale: Record that the current import-migration wave has been checked in and completed via pull request, and set the next refactor slice to start on a new branch. -impact: Clear project continuity and reduced risk of overlap between completed import migration work and upcoming `legacyActionsService` decomposition. -status: completed - -Summary: - -- Import migration wave is now completed, checked in, and PR’d. -- Latest commits in this wave include: - - `f0202bb` — viewall/search/unsubscribe focused imports - - `fa98535` — endpoint/file proxy focused imports - - `bef8f25` — stale legacy comment cleanup -- Next chunk is explicitly designated as a new-branch activity focused on splitting `actions/services/legacyActionsService.js` into smaller direct service/client modules. - -Validation: - -- Broad `.../actions` import scans now show no active matches in `.js` files (legacy references are comment-only/removed). -- Branch history confirms migration commits are present and ordered for safe rollback. - -Follow-ups: - -- Create new branch for Phase 5 decomposition work. -- Start with low-risk extraction slices from `legacyActionsService.js` (reference/search first), then portal/document batches. - ---- - -### CL-010: Phase 5 kickoff — first legacy split slice (search/reference direct modules) - -date: 2026-03-13 -author: Cline -scope: `actions/services/searchDirectService.js`, `actions/services/referenceDataDirectService.js`, `actions/services/{searchService,referenceDataService}.js` -type: change -rationale: Start Phase 5 decomposition on a new branch by extracting low-risk search/reference wrappers from `legacyActionsService.js` into direct domain modules while keeping service exports stable. -impact: Search/reference service exports now route through focused direct modules; compatibility signatures preserved for callers importing from service barrels. -status: completed - -Summary: - -- Created branch `TASK21997-phase5-legacyactions-split` from `SIPS-Development`. -- Added `searchDirectService.js` containing extracted search/address/document-search wrapper implementations. -- Added `referenceDataDirectService.js` containing extracted reference-data wrapper implementations. -- Updated `searchService.js` and `referenceDataService.js` to import from the new direct modules instead of `legacyActionsService`. - -Validation: - -- `npm run lint` (result unchanged): still fails due pre-existing Next/ESLint options incompatibility in repository tooling. -- Import checks confirm: - - `searchService.js` -> `./searchDirectService` - - `referenceDataService.js` -> `./referenceDataDirectService` -- Branch/status check confirms only Phase 5 slice files are modified on the new branch. - -Follow-ups: - -- Continue portal/document extraction slices from `legacyActionsService.js` in small batches. -- After each slice, re-point corresponding grouped service modules and remove dead wrappers once no longer referenced. - ---- - -### CL-011: Phase 5 document slice — direct document module extraction - -date: 2026-03-13 -author: Cline -scope: `actions/services/documentDirectService.js`, `actions/services/documentService.js`, `memory-bank/*` -type: change -rationale: Continue Phase 5 decomposition by extracting document/file wrappers from `legacyActionsService.js` into a dedicated direct module while preserving grouped service API compatibility. -impact: Document/file grouped service exports now route through focused direct implementation; legacy coupling reduced for document domain with no expected caller contract changes. -status: completed - -Summary: - -- Added `documentDirectService.js` with extracted blob/file upload, download, pdf, and container helpers. -- Re-pointed `documentService.js` imports to `./documentDirectService`. -- Kept export names and signatures unchanged at grouped service boundary. - -Validation: - -- Service import scan confirms `documentService.js` no longer imports from `legacyActionsService`. -- Remaining legacy-backed grouped modules: `portalService`, `accountService`, `caseService`, `adminService`, `notifyService`, `integrationService`. -- `npm run lint` completes with warnings only (no blocking errors). - -Follow-ups: - -- Next recommended slice: `portalDirectService` extraction, then `account/case`. -- Continue per-slice parity checks and legacy import reduction scan. - ---- - -### CL-012: Phase 5 portal slice — direct portal module extraction - -date: 2026-03-13 -author: Cline -scope: `actions/services/portalDirectService.js`, `actions/services/portalService.js` -type: change -rationale: Continue Phase 5 decomposition by extracting portal-domain wrappers from `legacyActionsService` into a direct module while preserving grouped service contract stability. -impact: Portal grouped exports now route through a focused direct module; reduced coupling to legacy monolith. -status: completed - -Summary: - -- Added `portalDirectService.js`. -- Updated `portalService.js` to import from `./portalDirectService`. - -Validation: - -- Legacy import scan reduced remaining `legacyActionsService`-backed grouped modules. -- `npm run lint` completes with warnings only. - -Follow-ups: - -- Extract account + case direct modules. - ---- - -### CL-013: Phase 5 account/case slice — direct module extraction - -date: 2026-03-13 -author: Cline -scope: `actions/services/{accountDirectService,caseDirectService,accountService,caseService}.js` -type: change -rationale: Continue Phase 5 by moving account and case wrappers out of legacy module into dedicated direct modules while keeping grouped service API stable. -impact: Account/case grouped services now point to direct implementations; further legacy decoupling. -status: completed - -Summary: - -- Added `accountDirectService.js` and `caseDirectService.js`. -- Re-pointed `accountService.js` and `caseService.js`. - -Validation: - -- Legacy import scan left only admin/integration/notify using legacy. -- `npm run lint` completes with warnings only. - -Follow-ups: - -- Extract admin + integration + notify direct modules. - ---- - -### CL-014: Phase 5 final extraction slice — admin/integration/notify direct modules - -date: 2026-03-13 -author: Cline -scope: `actions/services/{adminDirectService,integrationDirectService,notifyDirectService,adminService,integrationService,notifyService}.js` -type: change -rationale: Complete Phase 5 domain decomposition by extracting final legacy-backed grouped services into direct modules. -impact: All grouped service modules now route through direct implementations. -status: completed - -Summary: - -- Added `adminDirectService.js`, `integrationDirectService.js`, `notifyDirectService.js`. -- Re-pointed `adminService.js`, `integrationService.js`, `notifyService.js`. - -Validation: - -- `actions/services` scan reports zero `./legacyActionsService` imports. -- `npm run lint` completes with warnings only. - -Follow-ups: - -- Remove dead `legacyActionsService.js` implementation. - ---- - -### CL-015: Phase 5 cleanup — remove legacy actions service - -date: 2026-03-13 -author: Cline -scope: `actions/services/legacyActionsService.js` (deleted) -type: change -rationale: Finalize Phase 5 after full routing migration by removing dead legacy implementation module. -impact: Monolithic legacy service removed; architecture now uses grouped service façade + direct per-domain modules. -status: completed - -Summary: - -- Deleted `actions/services/legacyActionsService.js` after zero-reference verification. - -Validation: - -- Project scan confirms no `legacyActionsService` references in `.js` files. -- `npm run lint` completes with warnings only. -- `npm run build` succeeds. - -Follow-ups: - -- Begin next phase: post-split hardening/tests/logging cleanup. - ---- - -### CL-016: Phase 6 hardening — parity tests, safe dedupe, and logging cleanup - -date: 2026-03-13 -author: Cline -scope: `actions/services/*DirectService.js`, `actions/services/httpServiceUtils.js`, `tests/phase6/service-parity.test.cjs`, `memory-bank/*` -type: change -rationale: Start post-Phase-5 hardening by adding focused parity checks, reducing repeated axios/error-handling patterns without contract changes, and removing noisy logs in sensitive service paths. -impact: Improved maintainability and safety posture in service layer with preserved grouped-service signatures/return shapes; added regression guard for service export stability. -status: completed - -Summary: - -- Added `tests/phase6/service-parity.test.cjs` to verify: - - grouped service import/export parity for search/reference/document/portal/account/case/admin/integration/notify - - `actions/services/index.js` re-export list stability -- Added `actions/services/httpServiceUtils.js` with shared helpers: - - `logAndReturnResponse` - - `buildEmptyValueErrorResponse` - - `logAndReturnEmptyValueErrorResponse` -- Applied low-risk dedupe refactors in: - - `searchDirectService.js` - - `referenceDataDirectService.js` - - `caseDirectService.js` - - `adminDirectService.js` -- Removed debug `console.log` traces from sensitive/noisy direct service flows in: - - `searchDirectService.js` - - `documentDirectService.js` - - `portalDirectService.js` - - `caseDirectService.js` - - `adminDirectService.js` -- Added focused behavioural service test pack: - - `tests/phase6/service-behaviour.test.cjs` - - mocked axios and logger checks to assert success/error contract handling for selected critical functions. - -Validation: - -- `node tests/phase6/service-parity.test.cjs` -> pass -- `node tests/phase6/service-behaviour.test.cjs` -> pass (8/8) -- `npm run lint` -> warnings only (pre-existing warning set) -- Targeted smoke/negative checks on local dev server: - - `GET /advancedsearch` and `GET /cy/advancedsearch` -> 200 - - `GET /case` and `GET /cy/case` -> 200 - - `GET /myportal` and `GET /cy/myportal` -> 307 to `/auth/signin` (unauthenticated negative path) - - `GET /api/file/getbloblistproxy?container=test&casefolderID=test` -> 400 (negative path) - - `POST /api/email/notify` with `{}` -> 400 (negative path) - - `GET /searchresults` and `/cy/searchresults` -> 500 due pre-existing SSR serialization issue (`initialState.search.searchString` undefined) - -Follow-ups: - -- Investigate/fix pre-existing `/searchresults` SSR serialization issue before broader search smoke confidence sign-off. -- Optional next increment: extend behavioural coverage to document/portal/account/notify/integration direct-service contracts. - ---- - -### CL-017: Phase 7 hardening — search SSR fix + behavioural expansion for remaining service domains - -date: 2026-03-13 -author: Cline -scope: `pages/searchresults.js`, `tests/phase7/service-behaviour.test.cjs`, `memory-bank/*` -type: change -rationale: Start Phase 7 from a new branch based on `origin/SIPS-Development`, fix known pre-existing `/searchresults` SSR serialization failure, and extend behavioural/negative-path coverage for remaining direct-service domains. -impact: Search results SSR now safely serializes when query `q` is absent; behavioural confidence improved across document/portal/account/notify/integration service contracts with no signature/return-shape changes. -status: completed - -Summary: - -- Created branch: `TASK21988a-phase7-postphase6-hardening` (from `origin/SIPS-Development`). -- Fixed pre-existing SSR issue in `pages/searchresults.js` by changing: - - `setSearch(query.q)` -> `setSearch(query?.q || "")` -- Added `tests/phase7/service-behaviour.test.cjs` with mocked-axios behavioural assertions for: - - document - - portal - - account - - notify - - integration -- Included feasible negative-path checks for relay/hash/token-sensitive behavior patterns (hashed URL composition and existing per-function error contracts). - -Validation: - -- `node tests/phase6/service-parity.test.cjs` -> pass -- `node tests/phase6/service-behaviour.test.cjs` -> pass (8/8) -- `node tests/phase7/service-behaviour.test.cjs` -> pass (10/10) -- `npm run lint` -> warnings only, no new lint errors introduced -- Manual smoke/negative-path checks (local dev on `localhost:3001` due `3000` in use): - - `/searchresults`, `/cy/searchresults` -> 200 - - `/case`, `/cy/case` -> 200 - - `/myportal`, `/cy/myportal` -> 307 to `/auth/signin` - - `/api/file/getbloblistproxy?container=test&casefolderID=test` -> 400 - - `POST /api/email/notify` with `{}` -> 400 - -Follow-ups: - -- Continue incremental hardening in sensitive relay/hash/token flows without changing external contracts. -- Keep lint warning backlog separate from this refactor stream unless explicitly scoped. - -Rollback plan: - -- Revert `pages/searchresults.js` and remove `tests/phase7/service-behaviour.test.cjs` if regression is observed. - ---- - -### CL-018: Phase 8 hardening — hash enforcement and negative-path standardization in sensitive APIs - -date: 2026-03-13 -author: Cline -scope: `pages/api/file/{deleteblobcase,deleteblobrep,createappealcompletemessage_api}.js`, `pages/api/endpoint/getportallogin_api.js`, `actions/services/{documentDirectService,portalDirectService}.js`, `tests/phase8/service-behaviour.test.cjs`, `memory-bank/*` -type: change -rationale: Deliver a small reversible hardening slice by re-enforcing hash guards in high-risk handlers, standardizing invalid-input negative paths, and reducing noisy/sensitive logging while preserving external contracts. -impact: Stronger hash/integrity guard posture and consistent 400 negative paths for invalid/missing hash and required params; no intended response-shape or signature changes. -status: completed - -Summary: - -- Started from latest `origin/SIPS-Development` on new branch `TASK22017-phase8-hardening-slice`. -- Re-enabled/enforced hash validation in: - - `deleteblobcase` - - `deleteblobrep` - - `createappealcompletemessage_api` -- Standardized early 400 handling for missing required query params where feasible: - - container/casefolder/repfile/tempcaseref/emailAddress checks as applicable -- Hardened `getportallogin_api`: - - explicit early validation for email/hash before token fetch - - removed unnecessary lodash branch complexity while preserving output behavior -- Improved logging discipline in sensitive flow: - - removed noisy `console.log` traces from `createappealcompletemessage_api` - - switched error logging to `consoleLogger` -- Added parity updates required for existing callers after hash re-enforcement: - - `documentDirectService` now appends hash on `deleteblobcase` and `deleteblobrep` - - `portalDirectService` now appends hash for `createappealcompletemessage_api` call using existing hash path contract -- Added focused phase-8 tests: - - `tests/phase8/service-behaviour.test.cjs` - - covers invalid/missing hash and missing key inputs as applicable across the 4 target handlers - - includes one valid-hash happy-path contract check for `getportallogin_api` via mocks - -Validation: - -- `node tests/phase6/service-parity.test.cjs` -> pass -- `node tests/phase6/service-behaviour.test.cjs` -> pass (8/8) -- `node tests/phase7/service-behaviour.test.cjs` -> pass (10/10) -- `node tests/phase8/service-behaviour.test.cjs` -> pass (5/5) -- `npm run lint` -> warnings only (pre-existing `react-hooks/exhaustive-deps` warnings; no new lint errors) -- Manual HTTP checks (local server `http://localhost:3001`): - - invalid/missing hash for all 4 handlers -> 400 - - missing required key params where tested -> 400 - - valid-hash spot-check (`getportallogin_api`) still returned 400 due upstream relay/CRM behavior in local env (hash gate passed, downstream dependency failed) - -Follow-ups: - -- Investigate local relay/CRM dependency behavior for `getportallogin_api` happy path in integrated environment. -- Continue incremental hash/negative-path hardening for other sensitive `pages/api/file/**` handlers still carrying commented bypass patterns. - -Rollback plan: - -- Revert the four hardened API files and the two direct-service hash append updates. -- Remove `tests/phase8/service-behaviour.test.cjs` if the full phase-8 slice is rolled back. -- Re-run phase6/phase7 baseline tests and lint to confirm rollback parity. - ---- - -### CL-019: Phase 9 hardening — additional file-handler hash enforcement slice - -date: 2026-03-13 -author: Cline -scope: `pages/api/file/{createrepcompletemessage_api,upload,uploadsinglefile,setupcontainer}.js`, `actions/services/{portalDirectService,documentDirectService}.js`, `tests/phase9/service-behaviour.test.cjs`, `memory-bank/*` -type: change -rationale: Continue incremental hardening with a small reversible slice focused on additional sensitive file handlers still showing bypassed/commented hash checks or inconsistent negative-path behavior. -impact: Stronger hash/integrity guard posture and standardized 400 negative paths for invalid/missing hash and key params; no intended signature or response-shape contract changes. -status: completed - -Summary: - -- Started from latest `origin/SIPS-Development` on branch `TASK22019-phase-9-hardening`. -- Re-enabled/enforced hash validation and early 400 guards in: - - `createrepcompletemessage_api` - - `upload` - - `uploadsinglefile` - - `setupcontainer` -- Reduced noisy logs in sensitive paths and retained structured error logging where applicable. -- Added required caller parity updates: - - `portalDirectService.sendRepCompleteMessage` now appends hash - - `documentDirectService.uploadFiles/uploadRepFiles/uploadSingleFile` now append hash -- Added focused phase-9 tests: - - `tests/phase9/service-behaviour.test.cjs` - - negative-path coverage for the 4 selected phase-9 handlers - -Validation: - -- `node tests/phase6/service-parity.test.cjs` -> pass -- `node tests/phase6/service-behaviour.test.cjs` -> pass (8/8) -- `node tests/phase7/service-behaviour.test.cjs` -> pass (10/10) -- `node tests/phase8/service-behaviour.test.cjs` -> pass (5/5) -- `node tests/phase9/service-behaviour.test.cjs` -> pass (5/5) -- `npm run lint` -> warnings only (pre-existing `react-hooks/exhaustive-deps` warnings; no new lint errors) -- Manual HTTP negative-path checks on `localhost:3000`: - - missing/invalid hash for each selected handler -> 400 - - missing required key params where tested -> 400 -- Valid-hash HTTP spot-check: - - `POST /api/file/uploadsinglefile?hash=` -> 200 (hash generated from `.env.local` key) - -Follow-ups: - -- Continue incremental hardening slices for remaining sensitive handlers with commented/bypassed hash checks. - -Rollback plan: - -- Revert the 4 hardened API handlers and 2 caller parity service files. -- Remove `tests/phase9/service-behaviour.test.cjs` if rolling back full phase-9 slice. -- Re-run phase6/7/8/9 tests and lint to confirm rollback parity. - ---- - -### CL-020: Phase 10 hardening — file retrieval handlers negative-path standardization - -date: 2026-03-13 -author: Cline -scope: `pages/api/file/{getawaitingsubmissionfromblob,getprogressobjblob,getbloblist,getrepsblob}.js`, `tests/phase10/service-behaviour.test.cjs`, `memory-bank/*` -type: change -rationale: Continue connected hardening slices on the same work-item branch, targeting additional sensitive file retrieval handlers with inconsistent early guards and legacy commented hash/debug handling. -impact: Stronger and more consistent 400 negative-path behavior for missing/invalid hash and missing key params, with no intended signature or response-shape contract changes. -status: completed - -Summary: - -- Continued from Phase 9 on branch `TASK22019-phase-9-hardening`. -- Hardened 4 additional handlers: - - `getawaitingsubmissionfromblob` - - `getprogressobjblob` - - `getbloblist` - - `getrepsblob` -- Added explicit early guards for required query/hash inputs. -- Standardized hash mismatch handling to early 400 return. -- Removed legacy commented debug blocks in touched handlers. -- Added focused phase-10 tests: - - `tests/phase10/service-behaviour.test.cjs` - - includes negative-path coverage for all 4 handlers and one valid-hash mocked happy path. - -Validation: - -- `node tests/phase6/service-parity.test.cjs` -> pass -- `node tests/phase6/service-behaviour.test.cjs` -> pass (8/8) -- `node tests/phase7/service-behaviour.test.cjs` -> pass (10/10) -- `node tests/phase8/service-behaviour.test.cjs` -> pass (5/5) -- `node tests/phase9/service-behaviour.test.cjs` -> pass (5/5) -- `node tests/phase10/service-behaviour.test.cjs` -> pass (5/5) -- `npm run lint` -> warnings only (pre-existing `react-hooks/exhaustive-deps` warnings) -- Manual HTTP checks (`localhost:3000`): - - missing hash for each selected phase-10 handler -> 400 - - valid hash `getbloblist` spot-check -> 500 due local downstream/storage dependency constraints - -Follow-ups: - -- Continue next incremental slice for remaining sensitive handlers with commented/bypassed hash checks. - -Rollback plan: - -- Revert the 4 hardened API handlers. -- Remove `tests/phase10/service-behaviour.test.cjs` if rolling back full phase-10 slice. -- Re-run phase6/7/8/9/10 tests + lint to confirm rollback parity. - ---- - -### CL-021: Phase 11 hardening — delete/bloblist hash guard standardization - -date: 2026-03-13 -author: Cline -scope: `pages/api/file/{getbloblist,deleteblob,deleteawaitingsubmissionfromblob}.js`, `tests/phase11/service-behaviour.test.cjs`, `memory-bank/*` -type: change -rationale: Continue connected hardening slices on the same work-item branch, targeting additional sensitive blob/delete handlers with inconsistent early guards and legacy commented traces. -impact: More consistent and explicit 400 negative-path handling for missing/invalid hash and key params, with no intended signature or response-shape contract changes. -status: completed - -Summary: - -- Continued on branch `TASK22019-phase-9-hardening`. -- Hardened 3 additional handlers: - - `getbloblist` - - `deleteblob` - - `deleteawaitingsubmissionfromblob` -- Added explicit early guards for required query/hash inputs. -- Standardized hash mismatch handling to early 400 return. -- Removed legacy commented debug traces in touched handlers. -- Added focused phase-11 tests: - - `tests/phase11/service-behaviour.test.cjs` - - includes negative-path coverage and one valid-hash mocked happy path. - -Validation: - -- `node tests/phase6/service-parity.test.cjs` -> pass -- `node tests/phase6/service-behaviour.test.cjs` -> pass (8/8) -- `node tests/phase7/service-behaviour.test.cjs` -> pass (10/10) -- `node tests/phase8/service-behaviour.test.cjs` -> pass (5/5) -- `node tests/phase9/service-behaviour.test.cjs` -> pass (5/5) -- `node tests/phase10/service-behaviour.test.cjs` -> pass (5/5) -- `node tests/phase11/service-behaviour.test.cjs` -> pass (4/4) -- `npm run lint` -> warnings only (pre-existing `react-hooks/exhaustive-deps` warnings) -- Manual HTTP checks (`localhost:3000`): - - missing/invalid hash for selected phase-11 handlers -> 400 - - valid-hash `getbloblist` spot-check -> 500 due local downstream/storage dependency constraints - -Follow-ups: - -- Continue next incremental slice for remaining sensitive handlers with commented/bypassed hash checks. - -Rollback plan: - -- Revert the 3 hardened API handlers. -- Remove `tests/phase11/service-behaviour.test.cjs` if rolling back full phase-11 slice. -- Re-run phase6/7/8/9/10/11 tests + lint to confirm rollback parity. - ---- - -### CL-022: Phase 12 hardening — download/proxy param and hash guard standardization - -date: 2026-03-13 -author: Cline -scope: `pages/api/file/{downloadblob,getbloblistproxy,getrepsblobproxy,getawaitingsubmissionfromblobproxy}.js`, `tests/phase12/service-behaviour.test.cjs`, `memory-bank/*` -type: change -rationale: Continue connected hardening slices on the same work-item branch, targeting additional sensitive download/proxy handlers with inconsistent early guards. -impact: More consistent and explicit 400 negative-path handling for missing/invalid hash and key params, with no intended signature or response-shape contract changes. -status: completed - -Summary: - -- Continued on branch `TASK22019-phase-9-hardening`. -- Hardened 4 additional handlers: - - `downloadblob` - - `getbloblistproxy` - - `getrepsblobproxy` - - `getawaitingsubmissionfromblobproxy` -- Added explicit early guards for required query/hash inputs. -- Standardized hash mismatch handling to early 400 return for `downloadblob`. -- Added focused phase-12 tests: - - `tests/phase12/service-behaviour.test.cjs` - - includes negative-path coverage and one valid-hash mocked happy path. - -Validation: - -- `node tests/phase6/service-parity.test.cjs` -> pass -- `node tests/phase6/service-behaviour.test.cjs` -> pass (8/8) -- `node tests/phase7/service-behaviour.test.cjs` -> pass (10/10) -- `node tests/phase8/service-behaviour.test.cjs` -> pass (5/5) -- `node tests/phase9/service-behaviour.test.cjs` -> pass (5/5) -- `node tests/phase10/service-behaviour.test.cjs` -> pass (5/5) -- `node tests/phase11/service-behaviour.test.cjs` -> pass (4/4) -- `node tests/phase12/service-behaviour.test.cjs` -> pass (4/4) -- `npm run lint` -> warnings only (pre-existing `react-hooks/exhaustive-deps` warnings) -- Manual HTTP checks (`localhost:3000`): - - missing/invalid inputs for selected phase-12 handlers -> 400 - - valid-hash `downloadblob` spot-check -> 500 due local downstream/storage dependency constraints - -Follow-ups: - -- Continue next incremental slice for remaining sensitive handlers with commented/bypassed hash checks. - -Rollback plan: - -- Revert the 4 hardened API handlers. -- Remove `tests/phase12/service-behaviour.test.cjs` if rolling back full phase-12 slice. -- Re-run phase6/7/8/9/10/11/12 tests + lint to confirm rollback parity. - ---- - -### CL-023: Phase 13 hardening — delete and involvement handler guard standardization - -date: 2026-03-13 -author: Cline -scope: `pages/api/file/{deleteblobcase,deleteblobrep,createcaseinvolvement_api,createrepinvolvement_api}.js`, `tests/phase13/service-behaviour.test.cjs`, `memory-bank/*` -type: change -rationale: Continue connected hardening slices on the same work-item branch, targeting additional sensitive delete/involvement handlers with inconsistent early guard and logging behavior. -impact: More consistent and explicit 400 negative-path handling for missing/invalid hash and required body keys, with no intended signature or response-shape contract changes. -status: completed - -Summary: - -- Continued on branch `TASK22019-phase-9-hardening`. -- Hardened 4 additional handlers: - - `deleteblobcase` - - `deleteblobrep` - - `createcaseinvolvement_api` - - `createrepinvolvement_api` -- Added explicit early guards for required hash/body inputs. -- Standardized hash mismatch handling to early 400 return for delete handlers. -- Removed noisy body/query logs from involvement handlers. -- Added focused phase-13 tests: - - `tests/phase13/service-behaviour.test.cjs` - - includes negative-path coverage and valid-input mocked happy paths. - -Validation: - -- `node tests/phase6/service-parity.test.cjs` -> pass -- `node tests/phase6/service-behaviour.test.cjs` -> pass (8/8) -- `node tests/phase7/service-behaviour.test.cjs` -> pass (10/10) -- `node tests/phase8/service-behaviour.test.cjs` -> pass (5/5) -- `node tests/phase9/service-behaviour.test.cjs` -> pass (5/5) -- `node tests/phase10/service-behaviour.test.cjs` -> pass (5/5) -- `node tests/phase11/service-behaviour.test.cjs` -> pass (4/4) -- `node tests/phase12/service-behaviour.test.cjs` -> pass (4/4) -- `node tests/phase13/service-behaviour.test.cjs` -> pass (7/7) -- `npm run lint` -> warnings only (pre-existing `react-hooks/exhaustive-deps` warnings) -- Manual HTTP checks (`localhost:3000`): - - missing/invalid inputs for selected phase-13 handlers -> 400 - - valid-hash `deleteblobcase` spot-check -> 500 due local downstream/storage dependency constraints - -Follow-ups: - -- Continue next incremental slice for remaining sensitive handlers with commented/bypassed hash checks. - -Rollback plan: - -- Revert the 4 hardened API handlers. -- Remove `tests/phase13/service-behaviour.test.cjs` if rolling back full phase-13 slice. -- Re-run phase6/7/8/9/10/11/12/13 tests + lint to confirm rollback parity. - ---- - -### CL-024: Phase 14 fix — authenticated server-side hash signing for browser callers - -date: 2026-03-13 -author: Cline -scope: `actions/services/{documentDirectService,portalDirectService}.js`, `pages/api/endpoint/gethash_api.js`, `tests/phase14/service-behaviour.test.cjs`, `memory-bank/*` -type: change -rationale: Fix runtime break in authenticated new-appeal journey where client-side hash generation attempted to use server-only `HASHKEY`. -impact: Restores browser flow while preserving hash-guard posture by moving hash generation to authenticated server endpoint; no intended external API contract changes. -status: completed - -Summary: - -- Added `gethash_api` endpoint to sign allow-listed API paths server-side. -- Endpoint enforces authenticated session and rejects unsupported paths. -- Updated direct services to fetch hash from signer endpoint for browser calls. -- Added server-side fallback hashing only when `HASHKEY` exists (non-browser contexts). -- Added phase-14 tests for missing-path, invalid-path, unauthenticated, and happy-path signer behavior. - -Validation: - -- `node tests/phase6/service-parity.test.cjs` -> pass -- `node tests/phase6/service-behaviour.test.cjs` -> pass -- `node tests/phase7/service-behaviour.test.cjs` -> pass -- `node tests/phase8/service-behaviour.test.cjs` -> pass -- `node tests/phase9/service-behaviour.test.cjs` -> pass -- `node tests/phase10/service-behaviour.test.cjs` -> pass -- `node tests/phase11/service-behaviour.test.cjs` -> pass -- `node tests/phase12/service-behaviour.test.cjs` -> pass -- `node tests/phase13/service-behaviour.test.cjs` -> pass -- `node tests/phase14/service-behaviour.test.cjs` -> pass (4/4) -- `npm run lint` -> warnings only (pre-existing warnings) - -Follow-ups: - -- Keep signer allow-list tight and expand only for explicitly required browser-side hash use cases. -- Continue removing legacy client-side direct hash assumptions as encountered. - ---- - -### CL-025: Phase 14 closeout follow-up — portal-login signer adoption + contract alignment fixes - -date: 2026-03-13 -author: Cline -scope: `actions/services/accountDirectService.js`, `pages/api/endpoint/gethash_api.js`, `tests/phase7/service-behaviour.test.cjs`, `tests/phase14/service-behaviour.test.cjs`, `pages/api/file/getrepsblob.js`, `components/elements/index.js`, `memory-bank/*` -type: change -rationale: Extend browser-safe hash signing to portal-login call path, keep signer allow-list explicit, and align an over-tightened file guard with actual endpoint contract discovered during runtime verification. -impact: Removes remaining browser-side hash risk in portal login path; preserves API response contracts while restoring route-accurate parameter validation and resolving Quill runtime import issue. -status: completed - -Summary: - -- Updated `accountDirectService.getPortalLogin` to use `/api/endpoint/gethash_api` for signed hash retrieval in browser contexts. -- Added `/api/endpoint/getportallogin_api` to signer endpoint allow-list in `gethash_api.js`. -- Updated tests to reflect signer-driven behavior and allow-list coverage: - - `tests/phase7/service-behaviour.test.cjs` - - `tests/phase14/service-behaviour.test.cjs` -- Applied follow-up runtime/contract fixes confirmed during manual verification: - - `pages/api/file/getrepsblob.js`: removed `casefolderID` hard requirement and pass-through argument to align with route usage (`container + hash`). - - `components/elements/index.js`: restored missing `updateLinks` import required by Quill-related flow. -- Branch pushed with follow-up commits: - - `6094874` - - `b8fa514` - -Validation: - -- `node tests/phase6/service-parity.test.cjs` -> pass -- `node tests/phase6/service-behaviour.test.cjs` -> pass -- `node tests/phase7/service-behaviour.test.cjs` -> pass (10/10) -- `node tests/phase8/service-behaviour.test.cjs` -> pass (5/5) -- `node tests/phase9/service-behaviour.test.cjs` -> pass (5/5) -- `node tests/phase10/service-behaviour.test.cjs` -> pass (5/5) -- `node tests/phase11/service-behaviour.test.cjs` -> pass (4/4) -- `node tests/phase12/service-behaviour.test.cjs` -> pass (4/4) -- `node tests/phase13/service-behaviour.test.cjs` -> pass (7/7) -- `node tests/phase14/service-behaviour.test.cjs` -> pass (5/5) -- `npm run lint` -> warnings only (pre-existing hook dependency warnings) - -Follow-ups: - -- Keep signer allow-list expansion minimal and task-driven. -- Continue replacing remaining browser-side direct hash assumptions only where flows require it. -- Confirm work-item/branch naming alignment for any subsequent phase slices if strict tracker continuity is required. - ---- - -### CL-026: Phase 15 hardening — consistency guards for additional hash-sensitive file handlers - -date: 2026-03-13 -author: Cline -scope: `pages/api/file/{upload,uploadsinglefile,createappealcompletemessage_api,setupcontainer}.js`, `tests/phase15/service-behaviour.test.cjs`, `memory-bank/*` -type: change -rationale: Deliver a small reversible consistency-only hardening slice by standardizing missing/invalid hash negative paths and required input handling in additional sensitive file handlers. -impact: Consistent early 400 behavior for missing/invalid hash and missing required params while preserving existing response shapes/signatures. -status: completed - -Summary: - -- Started new branch from `origin/SIPS-Development`: `TASK22028-phase15-hardening-slice`. -- Applied minimal hardening updates: - - `upload.js`: explicit missing-hash guard before hash comparison. - - `uploadsinglefile.js`: explicit missing-hash guard before hash comparison. - - `createappealcompletemessage_api.js`: added missing-hash guard to existing required-input guard block. - - `setupcontainer.js`: standardized to early-return on hash mismatch; contract and status behavior preserved. -- Added focused tests: - - `tests/phase15/service-behaviour.test.cjs` - - covers missing-hash negative paths for all selected handlers - - includes required-input negative paths and one valid-hash happy-path shape check. - -Validation: - -- `node tests/phase6/service-parity.test.cjs` -> pass -- `node tests/phase6/service-behaviour.test.cjs` -> pass (8/8) -- `node tests/phase7/service-behaviour.test.cjs` -> pass (10/10) -- `node tests/phase8/service-behaviour.test.cjs` -> pass (5/5) -- `node tests/phase9/service-behaviour.test.cjs` -> pass (5/5) -- `node tests/phase10/service-behaviour.test.cjs` -> pass (5/5) -- `node tests/phase11/service-behaviour.test.cjs` -> pass (4/4) -- `node tests/phase12/service-behaviour.test.cjs` -> pass (4/4) -- `node tests/phase13/service-behaviour.test.cjs` -> pass (7/7) -- `node tests/phase14/service-behaviour.test.cjs` -> pass (5/5) -- `node tests/phase15/service-behaviour.test.cjs` -> pass (5/5) -- `npm run lint` -> warnings only (pre-existing hook dependency warnings) -- Manual checks on `localhost:3002`: - - invalid/missing hash for each selected handler -> 400 - - missing required params where applicable -> 400 - - valid-hash spot-check (`setupcontainer`) -> 200 - -Follow-ups: - -- Continue small-batch consistency hardening for remaining sensitive handlers where guard patterns are still inconsistent. -- Keep manual happy-path checks constrained to feasible local dependencies; document downstream/environment-caused failures separately. - ---- - -### CL-027: Phase 16 hardening — file proxy required-input guard consistency slice - -date: 2026-03-13 -author: Cline -scope: `pages/api/file/{getbloblistproxy,getrepsblobproxy,getawaitingsubmissionfromblobproxy}.js`, `tests/phase16/service-behaviour.test.cjs`, `memory-bank/*` -type: change -rationale: Continue within the same branch using separate commits to apply a small consistency-only hardening slice for sensitive file proxy handlers. -impact: More consistent required-input validation and cleaner proxy handler internals without changing response-shape/signature contracts. -status: completed - -Summary: - -- Continued on `TASK22028-phase15-hardening-slice` as a separate commit. -- Standardized required-input guards using a local `hasValue` helper in 3 file proxy handlers. -- Removed unused imports/constants from touched files. -- Added `tests/phase16/service-behaviour.test.cjs` with negative-path coverage and one valid-input contract check. - -Validation: - -- `node tests/phase6/service-parity.test.cjs` -> pass -- `node tests/phase6/service-behaviour.test.cjs` -> pass (8/8) -- `node tests/phase7/service-behaviour.test.cjs` -> pass (10/10) -- `node tests/phase8/service-behaviour.test.cjs` -> pass (5/5) -- `node tests/phase9/service-behaviour.test.cjs` -> pass (5/5) -- `node tests/phase10/service-behaviour.test.cjs` -> pass (5/5) -- `node tests/phase11/service-behaviour.test.cjs` -> pass (4/4) -- `node tests/phase12/service-behaviour.test.cjs` -> pass (4/4) -- `node tests/phase13/service-behaviour.test.cjs` -> pass (7/7) -- `node tests/phase14/service-behaviour.test.cjs` -> pass (5/5) -- `node tests/phase15/service-behaviour.test.cjs` -> pass (5/5) -- `node tests/phase16/service-behaviour.test.cjs` -> pass (4/4) -- `npm run lint` -> warnings only (pre-existing) -- Manual checks (`localhost:3002`): missing required inputs across selected proxies -> 400 - -Follow-ups: - -- Continue incremental endpoint/file proxy consistency slices with same contract-preserving constraints. - ---- - -### CL-028: Follow-up fix — signer allow-list expanded for deleteblobcase browser path - -date: 2026-03-13 -author: Cline -scope: `pages/api/endpoint/gethash_api.js`, `tests/phase14/service-behaviour.test.cjs` -type: change -rationale: Resolve runtime failure where browser-side `deleteAwaitingSubmissionsFromBlob` hash signing requested a path not present in signer allow-list. -impact: Restores browser-safe hash signing for delete-blob-case flow without weakening auth/session guard on signer endpoint. -status: completed - -Summary: - -- Added `/api/file/deleteblobcase` to `gethash_api` allow-list. -- Added focused test coverage in phase-14 suite for the new allow-listed path. - -Validation: - -- `node tests/phase14/service-behaviour.test.cjs` -> pass (6/6) -- `node tests/phase7/service-behaviour.test.cjs` -> pass (10/10) -- `npm run lint` -> warnings only (pre-existing) - -Follow-ups: - -- Keep signer allow-list additions minimal and path-specific. - ---- - -### CL-029: Follow-up fix — signer coverage for additional delete flows - -date: 2026-03-13 -author: Cline -scope: `actions/services/{portalDirectService,documentDirectService}.js`, `pages/api/endpoint/gethash_api.js`, `tests/phase7/service-behaviour.test.cjs`, `tests/phase14/service-behaviour.test.cjs` -type: change -rationale: Resolve browser hash-signing gaps for additional delete operations still using direct client hash generation. -impact: Restores browser-safe signing for delete watched cases, delete my representations, and delete blob representation/awaiting-submission paths while retaining authenticated allow-list signer model. -status: completed - -Summary: - -- Updated signer allow-list to include: - - `/api/endpoint/deletemyrepresentations_api` - - `/api/endpoint/deletewatchedcases_api` - - `/api/file/deleteblobrep` -- Migrated direct service calls to signer-based hash retrieval for: - - `portalDirectService.deleteWatchedCases` - - `portalDirectService.deleteMyRepresentations` - - `documentDirectService.deleteAwaitingSubmissionsFromBlob` - - `documentDirectService.deleteMyRepresentationsFromBlob` -- Extended focused tests: - - `tests/phase7/service-behaviour.test.cjs` (service signer usage) - - `tests/phase14/service-behaviour.test.cjs` (allow-list coverage) - -Validation: - -- `node tests/phase7/service-behaviour.test.cjs` -> pass (12/12) -- `node tests/phase14/service-behaviour.test.cjs` -> pass (9/9) -- `npm run lint` -> warnings only (pre-existing) - -Follow-ups: - -- Keep allow-list expansion path-scoped and driven by concrete browser-call requirements only. - ---- - -### CL-030: Follow-up fix — myportal delete caseRef alignment + i18n namespace - -date: 2026-03-13 -author: Cline -scope: `components/myportal/{viewall,topthree_reps}.js`, `i18n.js`, `memory-bank/*` -type: change -rationale: Align representation delete calls to stable case reference identifier and resolve missing locale namespace mapping for new-appeal route context. -impact: Prevents delete-call identifier mismatches in myportal representation flows and restores expected translation namespace availability for `/newappeal/[appealtypes]`. -status: completed - -Summary: - -- Updated delete-representation callers to pass `caseRef` instead of display/ticket values in: - - `components/myportal/topthree_reps.js` - - `components/myportal/viewall.js` -- Included related view-all styling/class tidy updates and watched-case list refresh filtering adjustment. -- Added missing `myportal` namespace for route key: - - `i18n.js` -> `/newappeal/[appealtypes]` - -Validation: - -- `node tests/phase7/service-behaviour.test.cjs` -> pass (12/12) -- `npm run lint` -> warnings only (pre-existing) - -Follow-ups: - -- Keep delete calls consistently keyed on case reference across portal/view-all/top-three variants. - ---- - -### CL-031: Phase 17 closeout — remaining sensitive file handler consistency hardening - -date: 2026-03-13 -author: Cline -scope: `pages/api/file/{generatepdf,generateappealpdf,createappealcompletemessageproxy_api}.js`, `tests/phase17/service-behaviour.test.cjs`, `memory-bank/*` -type: change -rationale: Complete the remaining small hardening closeout slice in this stream by standardizing hash/input negative-path behavior and reducing noisy logging in the last priority-sensitive file handlers. -impact: Consistent 400 behavior for missing/invalid hash and missing required inputs in selected handlers; preserved response shapes/signatures. -status: completed - -Summary: - -- Branch created from `origin/SIPS-Development`: `TASK22057-phase17-hardening-closeout`. -- Hardened: - - `generatepdf.js` - - `generateappealpdf.js` - - `createappealcompletemessageproxy_api.js` -- Added early 400 guards for missing/invalid hash and required params where applicable. -- Removed noisy direct logging in touched handlers. -- Added focused test pack `tests/phase17/service-behaviour.test.cjs`. - -Validation: - -- `node tests/phase6/service-parity.test.cjs` -> pass -- `node tests/phase6/service-behaviour.test.cjs` -> pass (8/8) -- `node tests/phase7/service-behaviour.test.cjs` -> pass (12/12) -- `node tests/phase8/service-behaviour.test.cjs` -> pass (5/5) -- `node tests/phase9/service-behaviour.test.cjs` -> pass (5/5) -- `node tests/phase10/service-behaviour.test.cjs` -> pass (5/5) -- `node tests/phase11/service-behaviour.test.cjs` -> pass (4/4) -- `node tests/phase12/service-behaviour.test.cjs` -> pass (4/4) -- `node tests/phase13/service-behaviour.test.cjs` -> pass (7/7) -- `node tests/phase14/service-behaviour.test.cjs` -> pass (9/9) -- `node tests/phase15/service-behaviour.test.cjs` -> pass (5/5) -- `node tests/phase16/service-behaviour.test.cjs` -> pass (4/4) -- `node tests/phase17/service-behaviour.test.cjs` -> pass (6/6) -- `npm run lint` -> warnings only (pre-existing `react-hooks/exhaustive-deps` warnings) - -Follow-ups: - -- If desired, run additional integrated HTTP/manual checks in an environment with full relay/storage dependencies for end-to-end happy-path confirmation beyond mocked behaviour tests. - ---- - -### CL-032: Phase 18 additional consolidation slices — endpoint/file consistency and guard hygiene - -date: 2026-03-14 -author: Cline -scope: `pages/api/endpoint/{deletewatchedcases_api,getaccounts_api,getbasicsearchpaged_api,getappealpdfdocuments_api}.js`, `pages/api/file/{deleteblob,deleteawaitingsubmissionfromblob,getprogressobjblob,getbloblist,createcase_api,updatecase_api,editRepJson}.js`, `tests/phase18/service-behaviour.test.cjs`, `memory-bank/*` -type: change -rationale: Complete the user-requested three additional small, reversible hardening slices (logging hygiene, hash-guard flow consistency, and required-input guard consistency) without broad refactor or contract drift. -impact: Improves consistency of negative-path behavior and reduces noisy logging in selected sensitive handlers while preserving response/signature contracts. -status: completed - -Summary: - -- Implemented all three requested additional slices: - 1. endpoint logging/input hygiene - 2. file hash-guard flow consistency - 3. create/update input-guard + logging hygiene -- Endpoint updates: - - `deletewatchedcases_api`: added required `watchedCaseID` early 400 guard and removed direct URL logging. - - `getaccounts_api`: added required `emailAddress` early 400 guard and removed direct query logging. - - `getbasicsearchpaged_api`: added required `searchString` early 400 guard and removed noisy query logging. - - `getappealpdfdocuments_api`: added required `incidentid` early 400 guard and removed direct URL logging. -- File handler updates: - - standardized hash-check flow by removing redundant post-validation branches in: - - `deleteblob` - - `deleteawaitingsubmissionfromblob` - - `getprogressobjblob` - - `getbloblist` - - added required-input early 400 guards in: - - `createcase_api` (contact/appealType/container/lpa) - - `updatecase_api` (collection/appealObj/incident/body) - - removed noisy tag logging in `editRepJson`. -- Added focused test pack: - - `tests/phase18/service-behaviour.test.cjs` with negative-path and contract-preserving happy-path checks (8/8 pass). - -Validation: - -- `node tests/phase6/service-parity.test.cjs` -> pass -- `node tests/phase6/service-behaviour.test.cjs` -> pass (8/8) -- `node tests/phase7/service-behaviour.test.cjs` -> pass (12/12) -- `node tests/phase8/service-behaviour.test.cjs` -> pass (5/5) -- `node tests/phase9/service-behaviour.test.cjs` -> pass (5/5) -- `node tests/phase10/service-behaviour.test.cjs` -> pass (5/5) -- `node tests/phase11/service-behaviour.test.cjs` -> pass (4/4) -- `node tests/phase12/service-behaviour.test.cjs` -> pass (4/4) -- `node tests/phase13/service-behaviour.test.cjs` -> pass (7/7) -- `node tests/phase14/service-behaviour.test.cjs` -> pass (9/9) -- `node tests/phase15/service-behaviour.test.cjs` -> pass (5/5) -- `node tests/phase16/service-behaviour.test.cjs` -> pass (4/4) -- `node tests/phase17/service-behaviour.test.cjs` -> pass (6/6) -- `node tests/phase18/service-behaviour.test.cjs` -> pass (8/8) -- `npm run lint` -> warnings only (pre-existing `react-hooks/exhaustive-deps` warnings) - -Follow-ups: - -- Optional: execute integrated manual HTTP matrix for phase-18 touched handlers in an environment with full relay/storage dependencies for non-mocked happy-path verification. - ---- - -### CL-033: Phase 19 endpoint consistency slice — createwatchedcases guard hardening + noisy log cleanup - -date: 2026-03-14 -author: Cline -scope: `pages/api/endpoint/{createwatchedcases_api,getappealtypes_api,getdnslist_api}.js`, `tests/phase19/service-behaviour.test.cjs`, `memory-bank/*` -type: change -rationale: Deliver a small reversible consistency-only slice for selected sensitive endpoint handlers by standardizing invalid required input handling and removing noisy logging without changing contracts. -impact: Improves negative-path consistency and logging hygiene for selected handlers; response signatures/shapes preserved. -status: completed - -Summary: - -- `createwatchedcases_api` now consistently rejects missing/malformed required `@odata.bind` values with early 400. -- Removed noisy query URL logging in: - - `getappealtypes_api` - - `getdnslist_api` -- Added focused behavioural test pack: - - `tests/phase19/service-behaviour.test.cjs` (5 tests) - -Validation: - -- `node tests/phase6/service-parity.test.cjs` -> pass -- `node tests/phase6/service-behaviour.test.cjs` -> pass (8/8) -- `node tests/phase7/service-behaviour.test.cjs` -> pass (12/12) -- `node tests/phase8/service-behaviour.test.cjs` -> pass (5/5) -- `node tests/phase9/service-behaviour.test.cjs` -> pass (5/5) -- `node tests/phase10/service-behaviour.test.cjs` -> pass (5/5) -- `node tests/phase11/service-behaviour.test.cjs` -> pass (4/4) -- `node tests/phase12/service-behaviour.test.cjs` -> pass (4/4) -- `node tests/phase13/service-behaviour.test.cjs` -> pass (7/7) -- `node tests/phase14/service-behaviour.test.cjs` -> pass (9/9) -- `node tests/phase15/service-behaviour.test.cjs` -> pass (5/5) -- `node tests/phase16/service-behaviour.test.cjs` -> pass (4/4) -- `node tests/phase17/service-behaviour.test.cjs` -> pass (6/6) -- `node tests/phase18/service-behaviour.test.cjs` -> pass (8/8) -- `node tests/phase19/service-behaviour.test.cjs` -> pass (5/5) -- `npm run lint` -> warnings only (pre-existing hook dependency warnings) - -Follow-ups: - -- Continue same small-batch consistency pattern for remaining sensitive endpoint handlers only where clear guard/logging drift exists. - ---- - -### CL-034: Phase 20 endpoint consistency slice — dns/basic-search guard + logging cleanup - -date: 2026-03-14 -author: Cline -scope: `pages/api/endpoint/{getbasicdnssearch_api,getbasicdnsurlsearch_api,getbasicsearchdetailspaged_api}.js`, `tests/phase20/service-behaviour.test.cjs`, `memory-bank/*` -type: change -rationale: Deliver a small reversible consistency-only slice by removing noisy logging and standardizing required-input negative-path handling in additional sensitive endpoint handlers. -impact: Improves endpoint negative-path consistency and logging hygiene while preserving response signatures/shapes. -status: completed - -Summary: - -- Removed noisy `console.log` query logging in `getbasicdnssearch_api`. -- Added early 400 handling for missing/empty `searchString` in `getbasicdnsurlsearch_api`. -- Added early 400 handling for missing required params (`appealTypeName`, `primaryIdAttribute`, `incidentID`) in `getbasicsearchdetailspaged_api`. -- Added focused behavioural test pack: - - `tests/phase20/service-behaviour.test.cjs` (5 tests) - -Validation: - -- `node tests/phase6/service-parity.test.cjs` -> pass -- `node tests/phase6/service-behaviour.test.cjs` -> pass (8/8) -- `node tests/phase7/service-behaviour.test.cjs` -> pass (12/12) -- `node tests/phase8/service-behaviour.test.cjs` -> pass (5/5) -- `node tests/phase9/service-behaviour.test.cjs` -> pass (5/5) -- `node tests/phase10/service-behaviour.test.cjs` -> pass (5/5) -- `node tests/phase11/service-behaviour.test.cjs` -> pass (4/4) -- `node tests/phase12/service-behaviour.test.cjs` -> pass (4/4) -- `node tests/phase13/service-behaviour.test.cjs` -> pass (7/7) -- `node tests/phase14/service-behaviour.test.cjs` -> pass (9/9) -- `node tests/phase15/service-behaviour.test.cjs` -> pass (5/5) -- `node tests/phase16/service-behaviour.test.cjs` -> pass (4/4) -- `node tests/phase17/service-behaviour.test.cjs` -> pass (6/6) -- `node tests/phase18/service-behaviour.test.cjs` -> pass (8/8) -- `node tests/phase19/service-behaviour.test.cjs` -> pass (5/5) -- `node tests/phase20/service-behaviour.test.cjs` -> pass (5/5) -- `npm run lint` -> warnings only (pre-existing hook dependency warnings) - -Follow-ups: - -- Continue same small-batch consistency pattern for remaining endpoint handlers where required-input/logging drift is clear. - ---- - -### CL-035: TASK22102 API contract consistency — Slice 1 (response helper + email/admin pilot) - -date: 2026-03-17 -author: Cline -scope: `pages/api/middleware/apiResponse.js`, `pages/api/email/{notify,getmailinglist}.js`, `pages/api/admin/{getnewappeals_api,getlatestdocuments_api}.js`, `memory-bank/*` -type: change -rationale: Start API contract-consistency program with a low-risk pilot slice introducing shared response helpers and replacing raw error passthrough in selected email/admin handlers. -impact: Improves response contract consistency and prevents raw error payload leakage in pilot handlers while preserving existing success-body compatibility. -status: completed - -Summary: - -- Added shared API response helper module: - - `pages/api/middleware/apiResponse.js` - - `respondSuccess(res, data, status)` - - `respondError(res, { status, code, message, details })` -- Migrated first slice handlers to helper-based responses: - - `pages/api/email/notify.js` - - `pages/api/email/getmailinglist.js` - - `pages/api/admin/getnewappeals_api.js` - - `pages/api/admin/getlatestdocuments_api.js` -- Contract updates in slice: - - replaced `res.status(400).json(error)` with structured error envelope - - replaced direct `res.status(200).json(...)` with `respondSuccess(...)` - - kept success payload shape as existing data object for non-breaking rollout - -Validation: - -- `npx next lint --file pages/api/middleware/apiResponse.js --file pages/api/email/notify.js --file pages/api/email/getmailinglist.js --file pages/api/admin/getnewappeals_api.js --file pages/api/admin/getlatestdocuments_api.js` -> pass (no warnings/errors) - -Follow-ups: - -- Slice 2 should migrate remaining email handlers (`getcaseref`, `getall`, `getevents`, `getdocuments`) to helper responses. -- After email/admin completion, expand to selected high-risk file handlers using same non-breaking helper model. - ---- - -### CL-036: TASK22102 API contract consistency — Slice 2 (remaining email handlers) - -date: 2026-03-17 -author: Cline -scope: `pages/api/email/{getcaseref,getall,getevents,getdocuments}.js` -type: change -rationale: Complete the email-domain response-contract consistency rollout by moving remaining handlers to shared helper-based success/error responses. -impact: Removes raw error passthrough in remaining email handlers and standardizes structured error envelopes while preserving success payload compatibility. -status: completed - -Summary: - -- Migrated remaining email handlers to shared response helper usage: - - `getcaseref` - - `getall` - - `getevents` - - `getdocuments` -- Replaced direct `res.status(...).json(...)` branches with: - - `respondSuccess(...)` - - `respondError(...)` -- Added stable error codes/messages for expected negative paths and catch branches. - -Validation: - -- `npx next lint --file pages/api/email/getcaseref.js --file pages/api/email/getevents.js --file pages/api/email/getdocuments.js --file pages/api/email/getall.js` -> pass (no warnings/errors) - -Follow-ups: - -- Next slice can target selected file handlers for equivalent response contract cleanup. - ---- - -### CL-037: TASK22102 API contract consistency — Slice 3 (file proxy handlers) - -date: 2026-03-17 -author: Cline -scope: `pages/api/file/{getbloblistproxy,getrepsblobproxy,getawaitingsubmissionfromblobproxy,createappealcompletemessageproxy_api}.js` -type: change -rationale: Extend contract consistency into selected proxy file handlers by replacing raw error passthrough and empty 400s with standardized structured responses. -impact: Improves API error contract clarity for selected file proxy routes while preserving success payload pass-through behavior. -status: completed - -Summary: - -- Migrated selected file proxy handlers to shared response helper usage: - - `getbloblistproxy` - - `getrepsblobproxy` - - `getawaitingsubmissionfromblobproxy` - - `createappealcompletemessageproxy_api` -- Replaced direct `res.status(...).json(...)` handling with: - - `respondSuccess(...)` - - `respondError(...)` -- Added explicit structured 400 responses for missing required query values and proxy fetch failures. - -Validation: - -- `npx next lint --file pages/api/file/getbloblistproxy.js --file pages/api/file/getrepsblobproxy.js --file pages/api/file/getawaitingsubmissionfromblobproxy.js --file pages/api/file/createappealcompletemessageproxy_api.js` -> pass (no warnings/errors) - -Follow-ups: - -- Next slice should target non-proxy file handlers that still return raw `error` payloads. - ---- - -### CL-038: TASK22102 API contract consistency — Slice 4 (security hardening + larger non-proxy file set) - -date: 2026-03-17 -author: Cline -scope: `pages/api/middleware/apiResponse.js`, `pages/api/file/{createappealcompletemessage_api,updatecase_api,createcaseinvolvement_api,createrepinvolvement_api,createcase_api,generatepdf}.js` -type: change -rationale: Apply requested security hardening for error detail exposure and deliver a larger non-proxy file-handler slice to improve codex usage efficiency while keeping contract risk low. -impact: Suppresses sensitive `details` payloads in production, improves structured API consistency in selected non-proxy file handlers, and preserves existing success-path payload compatibility. -status: completed - -Summary: - -- Hardened shared error helper: - - `respondError` now omits `error.details` when `NODE_ENV === "production"`. - - debug detail visibility remains available in non-production environments. -- Migrated a larger batch of non-proxy file handlers to helper-based responses: - - `createappealcompletemessage_api` - - `updatecase_api` - - `createcaseinvolvement_api` - - `createrepinvolvement_api` - - `createcase_api` - - `generatepdf` -- Standardized missing-input/hash/failure paths to structured `respondError` codes/messages while retaining success bodies and existing 200 semantics (including 412->record exists handling in involvement endpoints). - -Validation: - -- `npx next lint --file pages/api/middleware/apiResponse.js --file pages/api/file/createappealcompletemessage_api.js --file pages/api/file/updatecase_api.js --file pages/api/file/createcaseinvolvement_api.js --file pages/api/file/createrepinvolvement_api.js --file pages/api/file/createcase_api.js --file pages/api/file/generatepdf.js` -> pass (no warnings/errors) - -Follow-ups: - -- Continue next larger slice on remaining non-proxy file handlers still returning raw error payloads. - ---- - -### CL-039: TASK22102 API contract consistency — Slice 5 (larger file-handler batch) - -date: 2026-03-17 -author: Cline -scope: `pages/api/file/{uploadsinglefile,setupcontainer,createrepcompletemessage_api,editRepJson}.js` -type: change -rationale: Continue with a larger efficiency-focused slice by migrating remaining high-signal file handlers that still returned raw/empty error responses. -impact: Improves response-contract consistency and avoids leaking raw error payloads in selected file handlers while preserving success behavior and endpoint semantics. -status: completed - -Summary: - -- Migrated additional file handlers to helper-based responses: - - `uploadsinglefile` - - `setupcontainer` - - `createrepcompletemessage_api` - - `editRepJson` -- Replaced direct `res.status(...).json(...)` error branches (including raw `error` payload and empty responses) with structured: - - `respondError(...)` - - `respondSuccess(...)` -- Preserved existing success semantics: - - `uploadsinglefile` still returns uploaded result + `invalidFiles` - - `setupcontainer` still returns `{ data: "success", output }` - - `editRepJson` still returns success message on completion - -Validation: - -- `npx next lint --file pages/api/file/uploadsinglefile.js --file pages/api/file/setupcontainer.js --file pages/api/file/createrepcompletemessage_api.js --file pages/api/file/editRepJson.js` -> pass (no warnings/errors) - -Follow-ups: - -- Continue next larger slice on remaining file handlers with empty 400 responses to complete contract-consistency rollout. - ---- - -### CL-040: TASK22102 API contract consistency — Slice 6 (CRUD/blob retrieval group) - -date: 2026-03-17 -author: Cline -scope: `pages/api/file/{deleteblob,deleteblobcase,deleteblobrep,deleteawaitingsubmissionfromblob,getprogressobjblob,getawaitingsubmissionfromblob,getrepsblob}.js` -type: change -rationale: Deliver the first of two remaining larger slices by standardizing response contracts across blob CRUD and retrieval handlers still using direct/empty response patterns. -impact: Improves consistency and safety of error responses in selected blob handlers while preserving existing success payload behavior and cache-control semantics. -status: completed - -Summary: - -- Migrated 7 blob CRUD/retrieval handlers to `respondSuccess`/`respondError`: - - `deleteblob` - - `deleteblobcase` - - `deleteblobrep` - - `deleteawaitingsubmissionfromblob` - - `getprogressobjblob` - - `getawaitingsubmissionfromblob` - - `getrepsblob` -- Replaced empty `400` and direct status responses with structured error envelopes including explicit codes/messages. -- Removed redundant post-hash equality branches where equivalent logic was already guaranteed after early guard checks. -- Preserved response behavior: - - existing success data payload shapes retained (`{ data: ... }` or direct data payloads) - - `getrepsblob` retains `Cache-Control: no-store` header. - -Validation: - -- `npx next lint --file pages/api/file/deleteblob.js --file pages/api/file/deleteblobcase.js --file pages/api/file/deleteblobrep.js --file pages/api/file/deleteawaitingsubmissionfromblob.js --file pages/api/file/getprogressobjblob.js --file pages/api/file/getawaitingsubmissionfromblob.js --file pages/api/file/getrepsblob.js` -> pass (no warnings/errors) - -Follow-ups: - -- Execute final Slice 7 for remaining complex handlers (`upload`, `getbloblist`, `downloadblob`, `generateappealpdf`) to complete the 2-slice finish plan. - ---- - -### CL-041: TASK22109 email API contract parity + phase21 expansion - -date: 2026-03-18 -author: Cline -scope: `pages/api/email/{getevents,getdocuments,getall,getmailinglist,getcaseref,notify}.js`, `tests/phase21/{api-contract-slice1,_shared,email-handler-contract}.test.cjs` -type: change -rationale: Extend standardized API response contract hardening into remaining email handlers and batch a larger in-scope test/cleanup slice so review is less fragmented while preserving runtime behavior. -impact: More consistent email API negative-path/error contracts, lower noisy logging in sensitive email flow, and stronger automated coverage for email handlers. -status: completed - -Summary: - -- Completed TASK22109 across three cohesive commits: - - `6610e5c` — email API contract cleanup + initial phase21 email coverage - - `d17f3a1` — expanded email contract coverage + logging hygiene - - `e9cf1cf` — final mini-slice tidy + notify negative-path tests -- Email handler cleanup/hardening updates: - - removed stale debug/commented logging and dead variables/imports in selected email handlers - - replaced noisy `console.log` usage in `notify.js` with structured `consoleLogger` redacted event log - - retained existing success payload behavior; no intended response-shape breaking changes -- Phase21 test expansion: - - added dedicated `email-handler-contract.test.cjs` - - combined runner now executes helper + file-handler + email-handler suites - - `_shared.cjs` loader improved to handle additional `export default async function` module forms - - email suite now covers: - - `getevents` (required input, missing linked record, catch path) - - `getdocuments` (required input, catch path) - - `getall` (top-level catch path) - - `getmailinglist` (success + failure) - - `getcaseref` (success + failure) - - `notify` (missing email + notify failure) - -Validation: - -- `node tests/phase21/api-contract-slice1.test.cjs` -> pass - - helper: 4/4 - - file-handler: 11/11 - - email-handler: 12/12 -- `npm run lint` -> warnings only (pre-existing `react-hooks/exhaustive-deps` warnings) - -Follow-ups: - -- Open/merge TASK22109 PR (if not already merged). -- Next candidate stream: apply same contract+coverage pattern to selected `pages/api/endpoint/**` handlers still carrying noisy logging or thin negative-path coverage. - ---- - -### CL-042: TASK22168 endpoint account contract consistency slice (phase21) - -date: 2026-03-19 -author: Cline -scope: `pages/api/endpoint/{getaccounts_api,getemailaccountcheck_api,getpreferredlanguage_api}.js`, `tests/phase21/{api-contract-slice1,endpoint-handler-contract}.test.cjs`, `memory-bank/*` -type: change -rationale: Continue the post-TASK22109 API contract consistency stream with a low-risk, reversible endpoint slice focused on account lookup handlers, removing noisy/dead patterns and standardizing negative-path error envelopes while preserving success contracts. -impact: Consistent structured 400 error responses for missing required input and catch/failure paths in selected endpoint handlers; no intended success payload contract changes. -status: completed - -Summary: - -- Created branch from `origin/SIPS-Development`: - - `TASK22168-endpoint-account-contract-consistency` -- Updated endpoint handlers: - - `getaccounts_api.js` - - `getemailaccountcheck_api.js` - - `getpreferredlanguage_api.js` -- Slice changes applied: - - removed unused imports/dead/commented debug remnants in touched handlers - - standardized missing `emailAddress` handling to structured 400 envelope: - - code: `EMAIL_ADDRESS_REQUIRED` - - standardized catch-path 400 envelopes: - - `ACCOUNTS_FETCH_FAILED` - - `EMAIL_ACCOUNT_CHECK_FAILED` - - `PREFERRED_LANGUAGE_FETCH_FAILED` - - kept success payload behavior stable by returning existing upstream `data` unchanged via `respondSuccess` -- Phase21 test expansion: - - added `tests/phase21/endpoint-handler-contract.test.cjs` - - extended `tests/phase21/api-contract-slice1.test.cjs` to include endpoint handler suite - - new endpoint tests cover missing required input + catch/failure paths, plus success-contract parity check for `getpreferredlanguage_api` - -Validation: - -- `node tests/phase21/api-contract-slice1.test.cjs` -> pass - - helper: 4/4 - - file-handler: 11/11 - - email-handler: 12/12 - - endpoint-handler: 7/7 -- `npm run lint` -> warnings only (pre-existing `react-hooks/exhaustive-deps` warnings; no new lint errors) - -Follow-ups: - -- Next coherent endpoint slice can target login-adjacent handler drift (`getlogin_api`) and/or another compact account endpoint group using the same phase21 contract pattern. - ---- - -### CL-043: TASK22168 Bundle C extension — login/portal/account adjacency sweep (phase21) - -date: 2026-03-19 -author: Cline -scope: `pages/api/endpoint/{getlogin_api,getportallogin_api,getportalloginproxy_api,getpersonalaccount_api}.js`, `tests/phase21/endpoint-handler-contract.test.cjs` -type: change -rationale: User requested a larger same-branch bundle while preserving low-risk contract-consistency scope in endpoint account/login adjacency handlers. -impact: Structured 400 negative-path envelopes and cleanup consistency across additional login/account handlers with success payload contract stability preserved. -status: completed - -Summary: - -- Continued on branch: `TASK22168-endpoint-account-contract-consistency`. -- Extended endpoint contract-consistency pattern to additional handlers: - - `getlogin_api.js` - - removed dead imports/noisy logging - - standardized required input errors (`EMAIL_ADDRESS_REQUIRED`, `PASSWORD_REQUIRED`) - - standardized catch path (`LOGIN_FETCH_FAILED`) - - `getportallogin_api.js` - - removed dead imports - - standardized missing hash and invalid hash paths (`HASH_REQUIRED`, `INVALID_HASH`) - - standardized catch path (`PORTAL_LOGIN_FETCH_FAILED`) - - `getportalloginproxy_api.js` - - removed dead imports/legacy conditional noise - - standardized required input error (`EMAIL_ADDRESS_REQUIRED`) - - standardized catch path (`PORTAL_LOGIN_PROXY_FETCH_FAILED`) - - `getpersonalaccount_api.js` - - removed dead imports/noisy logging - - standardized required input error (`CONTACT_ID_REQUIRED`) - - standardized catch path (`PERSONAL_ACCOUNT_FETCH_FAILED`) -- Phase21 endpoint suite expansion: - - `tests/phase21/endpoint-handler-contract.test.cjs` - - expanded from 7 to 18 tests to cover Bundle C handlers and success-parity checks for adjacent account endpoints. - -Validation: - -- `node tests/phase21/api-contract-slice1.test.cjs` -> pass - - helper: 4/4 - - file-handler: 11/11 - - email-handler: 12/12 - - endpoint-handler: 18/18 -- `npm run lint` -> warnings only (pre-existing `react-hooks/exhaustive-deps` warnings) - -Follow-ups: - -- Next slice can target additional endpoint proxy groups only if needed, but current account/login consistency scope is now a meaningful bundle on TASK22168. diff --git a/memory-bank/progress.md b/memory-bank/progress.md deleted file mode 100644 index 75847f97..00000000 --- a/memory-bank/progress.md +++ /dev/null @@ -1,955 +0,0 @@ -# Progress — PEDW FrontEnd - -## Completed / evidenced milestones - -- Bilingual routing structure is established with extensive Welsh rewrites and locale namespace mapping. -- Next-auth + Prisma SQL Server persistence is integrated for user/session lifecycle. -- Broad API surface exists for search, case, portal, admin, and file/document operations. -- CRM/relay hash pattern is implemented across many endpoint handlers. -- Recent shipped updates focused on: - - search/case back-navigation and breadcrumb behavior, - - DNS/view-all navigation logic, - - preferred-language handling for notify template selection, - - PDF formatting/hyperlink fixes, - - upload validation character updates. - -## Work in progress signals - -- Ongoing iterative fixes in breadcrumb/case-summary flows suggest navigation consistency is still being tuned. -- Mixed proxy/non-proxy endpoint implementations continue to evolve in parallel. -- Priority 1 refactor plan execution started for `actions/index.js` split (Phase 1 foundation complete). - -## Planned / partially implemented (inferred from code state) - -- Partial migration or coexistence of deployment/runtime patterns (Next runtime plus custom server artifacts). -- Continued refinement of document/email workflow behavior (template/language and formatting quality). -- Prioritized structural refactor backlog documented in `memory-bank/refactor-backlog.md`. - -## Known technical debt - -- `actions/services/legacyActionsService.js` still holds broad domain wrappers after Phase 1 extraction (core helpers now separated). -- Significant duplication of token/hash/relay logic across endpoint files. -- Inconsistent security/hash guard enforcement in some file routes. -- Sparse automated test coverage (`tests/` currently empty). -- Verbose logging in sensitive flows (auth/email/actions/file) increases privacy risk. - -## Latest update (2026-03-12) - -- Branch `0000-update-actions-monolith` created from development branch for Priority 1 refactor implementation. -- `actions/index.js` reduced to a compatibility barrel. -- New core helper modules added under `actions/core/`: - - `env.js` - - `logger.js` - - `hash.js` - - `token.js` - - `headers.js` -- Existing action wrappers moved to `actions/services/legacyActionsService.js` and continue to be exported via the barrel for compatibility. -- `actions/clients/` scaffolded for upcoming client extraction phase. -- Phase 2 service grouping completed with dedicated service files and `actions/services/index.js` barrel. -- Export parity check confirms grouped service modules cover all legacy exported action names. -- Phase 3 migration started by moving selected high-churn consumers and representative endpoint handlers to direct `actions/services/*` and `actions/core/*` imports. -- Phase 4 hardening baseline added with new guard helpers and redacted logging, adopted in selected notify/login/contact API handlers. -- Additional Priority 1 consumer migration pass completed for high-use portal/form/representation helpers: - - Updated direct service/core imports in: - - `components/admin/tabs/documents.js` - - `components/admin/tabs/storage.js` - - `components/admin/utils/serverside.js` - - `components/case/documents.js` - - `components/case/representation/representationComplete.js` - - `components/case/representation/representationElements.js` - - `components/elements/index.js` - - `components/myportal/awaitingsubmissionfromblob.js` - - `components/myportal/topthree.js` - - `components/myportal/topthree_reps.js` - - `components/utils/index.js` - - `lib/myportal/loadMyPortalAppealPage.js` - - `lib/newappeal/loadNewAppealPage.js` -- Additional Priority 1 consumer migration pass completed for view-all/search/unsubscribe flows: - - Updated direct service/core imports in: - - `components/myportal/viewall.js` - - `components/search/addresssearchresults.js` - - `pages/unsubscribe/[watchlistid].js` - - `pages/unsubscribeall/[watchlistid].js` -- Broad `actions` barrel import count reduced again; remaining non-comment usages are now concentrated in selected `pages/api/endpoint/*` and `pages/api/file/*` handlers. -- Additional Priority 1 endpoint/file proxy migration chunk completed: - - Updated imports in: - - `pages/api/endpoint/getmylpacases_api.js` - - `pages/api/endpoint/getbasicdnssearchpaged_api.js` - - `pages/api/endpoint/getsearchdocumentdetailspaged_api.js` - - `pages/api/endpoint/getbasicsearchpaged_api.js` - - `pages/api/file/getawaitingsubmissionfromblobproxy.js` - - `pages/api/file/getrepsblobproxy.js` - - `pages/api/file/getbloblistproxy.js` - - `pages/api/file/createappealcompletemessageproxy_api.js` - - Migrated from broad `../../../actions` imports to focused `actions/core/*` + service imports. - - Removed duplicated local hash helper in `getmylpacases_api.js` and reused `actions/core/hash`. -- Broad `actions` import scan now reports only comment-only references (no active broad imports in `.js` files). -- Lint check re-run outcome unchanged: `next lint` fails due legacy/unsupported ESLint options in repo tooling config (not introduced by this refactor pass). - -## Handover update (2026-03-13) - -- Priority 1 import-migration wave has been checked in and completed via pull request. -- Recent migration commits captured in this wave: - - `f0202bb` - - `fa98535` - - `bef8f25` -- Active broad `.../actions` imports are now eliminated from live `.js` code paths. -- Next refactor phase will begin on a **new branch** and focus on splitting `actions/services/legacyActionsService.js` into smaller direct implementation modules. -- Recommended decomposition order for the new branch: - 1. reference/search extraction - 2. portal/document extraction - 3. compatibility layer slimming + dead wrapper removal - -## Latest update (2026-03-13 — Phase 5 kickoff) - -- New branch created from `SIPS-Development`: `TASK21997-phase5-legacyactions-split`. -- Completed first Phase 5 decomposition slice from `legacyActionsService`: - - Added `actions/services/searchDirectService.js` - - Added `actions/services/referenceDataDirectService.js` - - Updated `actions/services/searchService.js` to source from `searchDirectService` - - Updated `actions/services/referenceDataService.js` to source from `referenceDataDirectService` -- Compatibility approach preserved: public grouped service exports and function signatures remain unchanged for callers. -- Validation status unchanged: - - `npm run lint` still fails due pre-existing Next/ESLint option incompatibility in repo tooling configuration. - -## Latest update (2026-03-13 — Phase 5 document slice) - -- Continued on branch `TASK21997-phase5-legacyactions-split`. -- Completed second decomposition slice from `legacyActionsService`: - - Added `actions/services/documentDirectService.js` - - Updated `actions/services/documentService.js` to source from `documentDirectService` -- Compatibility approach preserved: - - grouped service export names/signatures unchanged for consumers. -- Verification: - - service import scan now shows remaining legacy-backed grouped modules are: - - `portalService`, `accountService`, `caseService`, `adminService`, `notifyService`, `integrationService` - - `npm run lint` passes with warnings only (no blocking errors). - -## Latest update (2026-03-13 — Phase 5 completion) - -- Continued decomposition and completed all remaining slices on `TASK21997-phase5-legacyactions-split`: - - portal direct extraction - - account + case direct extraction - - admin + integration + notify direct extraction - - legacy cleanup/removal -- New direct modules now in place: - - `portalDirectService.js` - - `accountDirectService.js` - - `caseDirectService.js` - - `adminDirectService.js` - - `integrationDirectService.js` - - `notifyDirectService.js` -- `actions/services/legacyActionsService.js` removed after import parity checks. -- Validation evidence: - - `actions/services` import scan: zero `./legacyActionsService` references - - `npm run lint`: warnings only, no blocking errors - - `npm run build`: successful production build - -## Latest update (2026-03-13 — Phase 6 post-Phase-5 hardening, in progress) - -- Branch created from `SIPS-Development`: `TASK21998-phase6-postphase5-hardening`. -- Added focused parity checks for grouped/direct service stability and service index barrel stability: - - `tests/phase6/service-parity.test.cjs` - - validates grouped service import/export parity across: - - search, referenceData, document, portal, account, case, admin, integration, notify - - validates `actions/services/index.js` export list stability/order. -- Added shared service error helper: - - `actions/services/httpServiceUtils.js` - - centralizes common `consoleLogger + return error.response` and `ErrResponse` shape patterns. -- Applied low-risk duplication reduction in direct services (no signature/shape changes intended): - - `searchDirectService.js` - - `referenceDataDirectService.js` - - `caseDirectService.js` - - `adminDirectService.js` -- Logging cleanup/redaction-oriented hardening (sensitive-flow noisy logs removed): - - removed debug `console.log` statements from: - - `searchDirectService.js` - - `documentDirectService.js` - - `portalDirectService.js` - - `caseDirectService.js` - - `adminDirectService.js` - -### Validation snapshot (Phase 6) - -- `node tests/phase6/service-parity.test.cjs` -> **pass** -- `node tests/phase6/service-behaviour.test.cjs` -> **pass** (8/8) -- `npm run lint` -> **warnings only** (same pre-existing warnings) - -### Decision captured (Phase 6) - -- Agreed approach: keep parity guard tests **and** add focused behavioural unit tests in the current refactor stream (instead of deferring all behavioural checks to long-term roadmap). -- Implemented now: - - `tests/phase6/service-behaviour.test.cjs` - - mocked-axios behavioural checks for critical success/error contracts across search/reference/case/admin direct services. -- Wider behavioural expansion remains on roadmap for additional domains/functions. - -### Targeted smoke snapshot (local dev server) - -- Search flow: - - `GET /searchresults` (EN/CY) -> **500** in local env due existing serialization issue (`initialState.search.searchString` undefined in SSR payload), observed in `/tmp/phase6-dev.log`. - - `GET /advancedsearch` and `GET /cy/advancedsearch` -> **200** -- Case flow: - - `GET /case` and `GET /cy/case` -> **200** -- My Portal flow (negative-path): - - `GET /myportal` and `GET /cy/myportal` -> **307** redirect to `/auth/signin` (expected unauthenticated behavior) -- Document flow (negative-path): - - `GET /api/file/getbloblistproxy?container=test&casefolderID=test` -> **400** -- Notify flow (negative-path): - - `POST /api/email/notify` with `{}` -> **400** - -## Latest update (2026-03-13 — Phase 8 hardening slice) - -- New branch created from `origin/SIPS-Development` with work item prefix: - - `TASK22017-phase8-hardening-slice` -- Hardened four sensitive API handlers with minimal reversible guards: - - `pages/api/file/deleteblobcase.js` - - `pages/api/file/deleteblobrep.js` - - `pages/api/file/createappealcompletemessage_api.js` - - `pages/api/endpoint/getportallogin_api.js` -- Scope delivered: - - re-enabled/enforced hash checks where bypassed/commented - - standardized early 400 negative paths for missing/invalid required query inputs - - reduced noisy sensitive-path logging and routed errors through `consoleLogger` - - preserved function signatures and existing response-shape contracts -- Consumer parity updates (required to preserve behaviour after hash enforcement): - - `actions/services/documentDirectService.js` - - append hash for delete-blob-case/delete-blob-rep calls - - `actions/services/portalDirectService.js` - - append hash for create-appeal-complete-message call (hash path preserved to existing API contract) -- Added focused tests: - - `tests/phase8/service-behaviour.test.cjs` - - covers negative paths for all 4 handlers (missing/invalid hash and missing key params as applicable) - - includes one happy-path check for `getportallogin_api` with valid hash via mocked dependencies - -### Validation snapshot (Phase 8) - -- `node tests/phase6/service-parity.test.cjs` -> **pass** -- `node tests/phase6/service-behaviour.test.cjs` -> **pass** (8/8) -- `node tests/phase7/service-behaviour.test.cjs` -> **pass** (10/10) -- `node tests/phase8/service-behaviour.test.cjs` -> **pass** (5/5) -- `npm run lint` -> **warnings only** (pre-existing react-hooks dependency warnings; no new lint errors) - -### Manual HTTP checks (Phase 8) - -- Local dev server on `http://localhost:3001`. -- Negative-path checks: - - `GET /api/file/deleteblobcase?...` missing hash -> **400** - - `GET /api/file/deleteblobcase?...&hash=bad` -> **400** - - `GET /api/file/deleteblobrep?...` missing hash -> **400** - - `GET /api/file/deleteblobrep?...&hash=bad` -> **400** - - `GET /api/file/deleteblobrep?...` missing `repfile` -> **400** - - `GET /api/file/createappealcompletemessage_api?...` missing hash -> **400** - - `GET /api/file/createappealcompletemessage_api?...&hash=bad` -> **400** - - `GET /api/file/createappealcompletemessage_api?...` missing `tempcaseref` -> **400** - - `GET /api/endpoint/getportallogin_api?...` missing hash -> **400** - - `GET /api/endpoint/getportallogin_api?...&hash=bad` -> **400** - - `GET /api/endpoint/getportallogin_api?...` missing `emailAddress` -> **400** -- Valid-hash spot-check: - - `GET /api/endpoint/getportallogin_api?...&hash=` reached handler with valid hash but returned **400** from upstream relay/CRM call in local environment (expected environmental dependency risk, not hash-guard bypass). - -## Latest update (2026-03-13 — Phase 9 hardening slice) - -- New branch created from `origin/SIPS-Development` with work item prefix: - - `TASK22019-phase-9-hardening` -- Hardened four additional sensitive file handlers with minimal reversible changes: - - `pages/api/file/createrepcompletemessage_api.js` - - `pages/api/file/upload.js` - - `pages/api/file/uploadsinglefile.js` - - `pages/api/file/setupcontainer.js` -- Scope delivered: - - re-enabled/enforced hash validation where bypassed/commented - - added/standardized early 400 negative paths for missing/invalid hash and missing key parameters - - reduced noisy logging in sensitive file-upload/message paths - - preserved handler signatures and external response-shape contracts -- Consumer parity updates: - - `actions/services/portalDirectService.js` - - append hash for `createrepcompletemessage_api` call - - `actions/services/documentDirectService.js` - - append hash for `upload` and `uploadsinglefile` calls -- Added focused tests: - - `tests/phase9/service-behaviour.test.cjs` - - covers negative paths across all 4 phase-9 handlers - -### Validation snapshot (Phase 9) - -- `node tests/phase6/service-parity.test.cjs` -> **pass** -- `node tests/phase6/service-behaviour.test.cjs` -> **pass** (8/8) -- `node tests/phase7/service-behaviour.test.cjs` -> **pass** (10/10) -- `node tests/phase8/service-behaviour.test.cjs` -> **pass** (5/5) -- `node tests/phase9/service-behaviour.test.cjs` -> **pass** (5/5) -- `npm run lint` -> **warnings only** (pre-existing react-hooks warnings; no new lint errors) - -### Manual HTTP checks (Phase 9) - -- Negative-path checks on `localhost:3000`: - - `GET /api/file/createrepcompletemessage_api?...` missing hash -> **400** - - `GET /api/file/createrepcompletemessage_api?...&hash=bad` -> **400** - - `POST /api/file/upload` missing hash -> **400** - - `POST /api/file/upload?hash=bad` -> **400** - - `POST /api/file/uploadsinglefile` missing hash -> **400** - - `POST /api/file/uploadsinglefile?hash=bad` -> **400** - - `GET /api/file/setupcontainer?ident=...` missing hash -> **400** - - `GET /api/file/setupcontainer?ident=...&hash=bad` -> **400** - - `GET /api/file/setupcontainer?hash=bad` (missing ident) -> **400** -- Valid-hash happy-path spot-check: - - Completed using `.env.local` runtime key: `POST /api/file/uploadsinglefile?hash=` -> **200** - -### Rollback plan (Phase 9) - -1. Revert the four hardened API handlers. -2. Revert direct-service hash append changes in `documentDirectService` and `portalDirectService`. -3. Remove `tests/phase9/service-behaviour.test.cjs` if full slice rollback required. -4. Re-run phase6/7/8/9 baseline tests + lint after rollback. - -## Latest update (2026-03-13 — Phase 10 hardening slice) - -- Continued on branch: - - `TASK22019-phase-9-hardening` -- Hardened four additional sensitive file handlers with minimal reversible changes: - - `pages/api/file/getawaitingsubmissionfromblob.js` - - `pages/api/file/getprogressobjblob.js` - - `pages/api/file/getbloblist.js` - - `pages/api/file/getrepsblob.js` -- Scope delivered: - - added explicit early 400 handling for missing/empty required inputs (`container`, `casefolderID` where applicable, `hash`) - - standardized hash-mismatch negative-path checks to early return 400 - - removed legacy/noisy commented debug blocks from touched handlers - - preserved existing handler signatures and response-shape contracts -- Caller parity impact: - - no new caller changes required in this slice because direct-service consumers already append hash for these APIs. -- Added focused tests: - - `tests/phase10/service-behaviour.test.cjs` - - covers negative paths for all 4 selected phase-10 handlers - - includes one valid-hash contract-preserving happy-path check (`getbloblist` via mocked dependencies) - -### Validation snapshot (Phase 10) - -- `node tests/phase6/service-parity.test.cjs` -> **pass** -- `node tests/phase6/service-behaviour.test.cjs` -> **pass** (8/8) -- `node tests/phase7/service-behaviour.test.cjs` -> **pass** (10/10) -- `node tests/phase8/service-behaviour.test.cjs` -> **pass** (5/5) -- `node tests/phase9/service-behaviour.test.cjs` -> **pass** (5/5) -- `node tests/phase10/service-behaviour.test.cjs` -> **pass** (5/5) -- `npm run lint` -> **warnings only** (pre-existing react-hooks warnings; no new lint errors) - -### Manual HTTP checks (Phase 10) - -- Negative-path checks on `localhost:3000`: - - `GET /api/file/getawaitingsubmissionfromblob?container=test` (missing hash) -> **400** - - `GET /api/file/getprogressobjblob?container=test&casefolderID=case-1` (missing hash) -> **400** - - `GET /api/file/getbloblist?container=test&casefolderID=case-1` (missing hash) -> **400** - - `GET /api/file/getrepsblob?container=test&casefolderID=case-1` (missing hash) -> **400** -- Valid-hash happy-path spot-check: - - `GET /api/file/getbloblist?container=test&casefolderID=case-1&hash=` -> **500** - - expected due local storage/upstream dependency constraints, while confirming hash gate is no longer the failing check. - -### Rollback plan (Phase 10) - -1. Revert the four hardened API handlers. -2. Remove `tests/phase10/service-behaviour.test.cjs` if full phase-10 rollback required. -3. Re-run phase6/7/8/9/10 baseline tests + lint after rollback. - -## Latest update (2026-03-13 — Phase 11 hardening slice) - -- Continued on branch: - - `TASK22019-phase-9-hardening` -- Hardened three additional sensitive file handlers with minimal reversible changes: - - `pages/api/file/getbloblist.js` - - `pages/api/file/deleteblob.js` - - `pages/api/file/deleteawaitingsubmissionfromblob.js` -- Scope delivered: - - added explicit early 400 handling for missing/empty required query inputs (`container`, `casefolderID`, `blobname`, `hash` as applicable) - - standardized hash-mismatch negative-path checks to early return 400 - - removed legacy/noisy commented debug traces in touched handlers - - preserved existing handler signatures and response-shape contracts -- Caller parity impact: - - no new caller changes required in this slice; direct-service consumers already pass expected query/hash data. -- Added focused tests: - - `tests/phase11/service-behaviour.test.cjs` - - covers negative paths for selected phase-11 handlers - - includes one valid-hash contract-preserving happy-path check (`getbloblist` via mocked dependencies) - -### Validation snapshot (Phase 11) - -- `node tests/phase6/service-parity.test.cjs` -> **pass** -- `node tests/phase6/service-behaviour.test.cjs` -> **pass** (8/8) -- `node tests/phase7/service-behaviour.test.cjs` -> **pass** (10/10) -- `node tests/phase8/service-behaviour.test.cjs` -> **pass** (5/5) -- `node tests/phase9/service-behaviour.test.cjs` -> **pass** (5/5) -- `node tests/phase10/service-behaviour.test.cjs` -> **pass** (5/5) -- `node tests/phase11/service-behaviour.test.cjs` -> **pass** (4/4) -- `npm run lint` -> **warnings only** (pre-existing react-hooks warnings; no new lint errors) - -### Manual HTTP checks (Phase 11) - -- Negative-path checks on `localhost:3000`: - - `GET /api/file/getbloblist?container=test&casefolderID=case-1` (missing hash) -> **400** - - `GET /api/file/deleteblob?container=test&casefolderID=case-1&blobname=file.pdf` (missing hash) -> **400** - - `GET /api/file/deleteawaitingsubmissionfromblob?container=test&casefolderID=case-1&blobname=file.pdf` (missing hash) -> **400** - - `GET /api/file/deleteblob?container=test&casefolderID=case-1&hash=bad` (missing blobname/invalid hash) -> **400** -- Valid-hash happy-path spot-check: - - `GET /api/file/getbloblist?container=test&casefolderID=case-1&hash=` -> **500** - - expected due local storage/upstream dependency constraints, while confirming hash gate is no longer the failing check. - -### Rollback plan (Phase 11) - -1. Revert the three hardened API handlers. -2. Remove `tests/phase11/service-behaviour.test.cjs` if full phase-11 rollback required. -3. Re-run phase6/7/8/9/10/11 baseline tests + lint after rollback. - -## Latest update (2026-03-13 — Phase 12 hardening slice) - -- Continued on branch: - - `TASK22019-phase-9-hardening` -- Hardened four additional sensitive handlers with minimal reversible changes: - - `pages/api/file/downloadblob.js` - - `pages/api/file/getbloblistproxy.js` - - `pages/api/file/getrepsblobproxy.js` - - `pages/api/file/getawaitingsubmissionfromblobproxy.js` -- Scope delivered: - - added explicit early 400 handling for missing/empty required query inputs (`container`, `casefolderID`, `blobname`, `hash` as applicable) - - standardized hash-mismatch negative-path checks for `downloadblob` - - preserved existing function signatures and response-shape contracts -- Added focused tests: - - `tests/phase12/service-behaviour.test.cjs` - - covers negative paths for selected phase-12 handlers - - includes one valid-hash contract-preserving happy-path check (`downloadblob` via mocked dependencies) - -### Validation snapshot (Phase 12) - -- `node tests/phase6/service-parity.test.cjs` -> **pass** -- `node tests/phase6/service-behaviour.test.cjs` -> **pass** (8/8) -- `node tests/phase7/service-behaviour.test.cjs` -> **pass** (10/10) -- `node tests/phase8/service-behaviour.test.cjs` -> **pass** (5/5) -- `node tests/phase9/service-behaviour.test.cjs` -> **pass** (5/5) -- `node tests/phase10/service-behaviour.test.cjs` -> **pass** (5/5) -- `node tests/phase11/service-behaviour.test.cjs` -> **pass** (4/4) -- `node tests/phase12/service-behaviour.test.cjs` -> **pass** (4/4) -- `npm run lint` -> **warnings only** (pre-existing react-hooks warnings; no new lint errors) - -### Manual HTTP checks (Phase 12) - -- Negative-path checks on `localhost:3000`: - - `GET /api/file/downloadblob?container=test&casefolderID=case-1&blobname=file.pdf` (missing hash) -> **400** - - `GET /api/file/downloadblob?container=test&casefolderID=case-1&blobname=file.pdf&hash=bad` -> **400** - - `GET /api/file/getbloblistproxy?casefolderID=case-1` (missing container) -> **400** - - `GET /api/file/getrepsblobproxy` (missing container) -> **400** - - `GET /api/file/getawaitingsubmissionfromblobproxy` (missing container) -> **400** -- Valid-hash happy-path spot-check: - - `GET /api/file/downloadblob?container=test&casefolderID=case-1&blobname=file.pdf&hash=` -> **500** - - expected due local storage/upstream dependency constraints, while confirming hash gate is no longer the failing check. - -### Rollback plan (Phase 12) - -1. Revert the four hardened API handlers. -2. Remove `tests/phase12/service-behaviour.test.cjs` if full phase-12 rollback required. -3. Re-run phase6/7/8/9/10/11/12 baseline tests + lint after rollback. - -## Latest update (2026-03-13 — Phase 13 hardening slice) - -- Continued on branch: - - `TASK22019-phase-9-hardening` -- Hardened four additional sensitive handlers with minimal reversible changes: - - `pages/api/file/deleteblobcase.js` - - `pages/api/file/deleteblobrep.js` - - `pages/api/file/createcaseinvolvement_api.js` - - `pages/api/file/createrepinvolvement_api.js` -- Scope delivered: - - added explicit early 400 handling for missing/empty required query/body inputs (`hash`, `contactid`, `incidentid` as applicable) - - standardized hash-mismatch negative-path checks for delete-blob handlers - - removed noisy body/query logging in involvement handlers - - preserved existing function signatures and response-shape contracts -- Added focused tests: - - `tests/phase13/service-behaviour.test.cjs` - - covers negative paths for selected phase-13 handlers - - includes valid-hash/valid-body contract-preserving happy-path checks via mocked dependencies - -### Validation snapshot (Phase 13) - -- `node tests/phase6/service-parity.test.cjs` -> **pass** -- `node tests/phase6/service-behaviour.test.cjs` -> **pass** (8/8) -- `node tests/phase7/service-behaviour.test.cjs` -> **pass** (10/10) -- `node tests/phase8/service-behaviour.test.cjs` -> **pass** (5/5) -- `node tests/phase9/service-behaviour.test.cjs` -> **pass** (5/5) -- `node tests/phase10/service-behaviour.test.cjs` -> **pass** (5/5) -- `node tests/phase11/service-behaviour.test.cjs` -> **pass** (4/4) -- `node tests/phase12/service-behaviour.test.cjs` -> **pass** (4/4) -- `node tests/phase13/service-behaviour.test.cjs` -> **pass** (7/7) -- `npm run lint` -> **warnings only** (pre-existing react-hooks warnings; no new lint errors) - -### Manual HTTP checks (Phase 13) - -- Negative-path checks on `localhost:3000`: - - `GET /api/file/deleteblobcase?container=test&casefolderID=case-1` (missing hash) -> **400** - - `GET /api/file/deleteblobcase?container=test&casefolderID=case-1&hash=bad` -> **400** - - `GET /api/file/deleteblobrep?container=test&casefolderID=case-1&repfile=r.pdf` (missing hash) -> **400** - - `POST /api/file/createcaseinvolvement_api` with `{}` -> **400** - - `POST /api/file/createrepinvolvement_api` with `{}` -> **400** -- Valid-hash happy-path spot-check: - - `GET /api/file/deleteblobcase?container=test&casefolderID=case-1&hash=` -> **500** - - expected due local storage/upstream dependency constraints, while confirming hash gate is no longer the failing check. - -### Rollback plan (Phase 13) - -1. Revert the four hardened API handlers. -2. Remove `tests/phase13/service-behaviour.test.cjs` if full phase-13 rollback required. -3. Re-run phase6/7/8/9/10/11/12/13 baseline tests + lint after rollback. - -## Latest update (2026-03-13 — Phase 14 client-hash signing fix) - -- Continued on branch: - - `TASK22019-phase-9-hardening` -- Fixed authenticated user-journey runtime error during new appeal flow where client-side hashing tried to use server-only `HASHKEY`. -- Added authenticated server-side hash signer endpoint: - - `pages/api/endpoint/gethash_api.js` - - requires session (`getSession`), allow-lists supported API paths, returns `{ hash }`. -- Updated direct services to request hash from server signer for browser calls, with server-side fallback only when `HASHKEY` exists: - - `actions/services/documentDirectService.js` - - `actions/services/portalDirectService.js` -- Preserved existing API contracts and response shapes in file handlers. -- Added focused tests: - - `tests/phase14/service-behaviour.test.cjs` - - covers signer endpoint negative paths + authenticated happy path. - -### Validation snapshot (Phase 14) - -- `node tests/phase6/service-parity.test.cjs` -> **pass** -- `node tests/phase6/service-behaviour.test.cjs` -> **pass** (8/8) -- `node tests/phase7/service-behaviour.test.cjs` -> **pass** (10/10) -- `node tests/phase8/service-behaviour.test.cjs` -> **pass** (5/5) -- `node tests/phase9/service-behaviour.test.cjs` -> **pass** (5/5) -- `node tests/phase10/service-behaviour.test.cjs` -> **pass** (5/5) -- `node tests/phase11/service-behaviour.test.cjs` -> **pass** (4/4) -- `node tests/phase12/service-behaviour.test.cjs` -> **pass** (4/4) -- `node tests/phase13/service-behaviour.test.cjs` -> **pass** (7/7) -- `node tests/phase14/service-behaviour.test.cjs` -> **pass** (4/4) -- `npm run lint` -> **warnings only** (pre-existing hook dependency warnings) - -### Rollback plan (Phase 14) - -1. Revert `pages/api/endpoint/gethash_api.js`. -2. Revert direct-service hash signer usage in `documentDirectService.js` and `portalDirectService.js`. -3. Remove `tests/phase14/service-behaviour.test.cjs` if rolling back full phase-14 slice. -4. Re-run phase6–phase14 tests + lint. - -## Latest update (2026-03-13 — Phase 14 closeout follow-up) - -- Continued on branch: - - `TASK22019-phase-9-hardening` -- Completed follow-up hardening and contract-alignment after runtime verification: - - `actions/services/accountDirectService.js` - - `getPortalLogin` now uses authenticated signer endpoint (`/api/endpoint/gethash_api`) for browser-safe hash generation - - retains server-only fallback to local `hashAPIPath` when `HASHKEY` is available - - `pages/api/endpoint/gethash_api.js` - - allow-list expanded for `/api/endpoint/getportallogin_api` - - `pages/api/file/getrepsblob.js` - - removed enforced `casefolderID` guard and argument pass-through to align with route contract (`/api/file/getrepsblob?container=...`) - - `components/elements/index.js` - - added missing `updateLinks` import from `components/utils` to resolve Quill runtime error -- Tests updated: - - `tests/phase7/service-behaviour.test.cjs` - - updated `getPortalLogin` expectations for signer endpoint behavior - - `tests/phase14/service-behaviour.test.cjs` - - added allow-list coverage for signer path `/api/endpoint/getportallogin_api` - -### Validation snapshot (Phase 14 follow-up) - -- `node tests/phase6/service-parity.test.cjs` -> **pass** -- `node tests/phase6/service-behaviour.test.cjs` -> **pass** (8/8) -- `node tests/phase7/service-behaviour.test.cjs` -> **pass** (10/10) -- `node tests/phase8/service-behaviour.test.cjs` -> **pass** (5/5) -- `node tests/phase9/service-behaviour.test.cjs` -> **pass** (5/5) -- `node tests/phase10/service-behaviour.test.cjs` -> **pass** (5/5) -- `node tests/phase11/service-behaviour.test.cjs` -> **pass** (4/4) -- `node tests/phase12/service-behaviour.test.cjs` -> **pass** (4/4) -- `node tests/phase13/service-behaviour.test.cjs` -> **pass** (7/7) -- `node tests/phase14/service-behaviour.test.cjs` -> **pass** (5/5) -- `npm run lint` -> **warnings only** (pre-existing hook dependency warnings) - -### Risks + mitigations (follow-up) - -- Risk: signer endpoint over-expansion could broaden hash issuance. - - Mitigation: strict allow-list retained; only required `getportallogin_api` path added. -- Risk: tightened/changed guards could break existing caller contracts. - - Mitigation: `getrepsblob` guard aligned back to actual route contract; response shape unchanged. -- Risk: UI runtime dependency regressions during hardening verification. - - Mitigation: missing `updateLinks` import restored with minimal diff. - -### Rollback plan (follow-up) - -1. Revert signer-path migration commit `6094874` (or files: `accountDirectService.js`, `gethash_api.js`, `tests/phase7`, `tests/phase14`). -2. Revert contract/import alignment commit `b8fa514` (or files: `getrepsblob.js`, `components/elements/index.js`). -3. Re-run phase6–phase14 tests and lint to confirm rollback parity. - -### Rollback plan (Phase 8) - -1. Revert the four hardened API handlers. -2. Revert direct-service hash append changes in `documentDirectService` and `portalDirectService`. -3. Remove `tests/phase8/service-behaviour.test.cjs` if full slice rollback required. -4. Re-run phase6/7 baseline tests + lint after rollback. - -## Latest update (2026-03-13 — Phase 15 hardening slice) - -- New branch created from `origin/SIPS-Development` with confirmed work item prefix: - - `TASK22028-phase15-hardening-slice` -- Delivered a small consistency-only hardening slice across 4 additional sensitive file handlers: - - `pages/api/file/upload.js` - - `pages/api/file/uploadsinglefile.js` - - `pages/api/file/createappealcompletemessage_api.js` - - `pages/api/file/setupcontainer.js` -- Scope delivered: - - standardized explicit early 400 handling for missing hash in handlers where hash validation was present but missing-hash guard was inconsistent - - standardized guard style in `setupcontainer` to early-return on hash mismatch (same status/contract) - - standardized missing required hash handling in `createappealcompletemessage_api` - - preserved response shapes and signatures (no contract changes) -- Added focused phase-15 tests: - - `tests/phase15/service-behaviour.test.cjs` - - negative-path coverage for missing hash across all 4 handlers - - additional required-input checks where applicable - - one valid-hash happy-path contract check (`setupcontainer` -> 200 with existing response shape) - -### Validation snapshot (Phase 15) - -- `node tests/phase6/service-parity.test.cjs` -> **pass** -- `node tests/phase6/service-behaviour.test.cjs` -> **pass** (8/8) -- `node tests/phase7/service-behaviour.test.cjs` -> **pass** (10/10) -- `node tests/phase8/service-behaviour.test.cjs` -> **pass** (5/5) -- `node tests/phase9/service-behaviour.test.cjs` -> **pass** (5/5) -- `node tests/phase10/service-behaviour.test.cjs` -> **pass** (5/5) -- `node tests/phase11/service-behaviour.test.cjs` -> **pass** (4/4) -- `node tests/phase12/service-behaviour.test.cjs` -> **pass** (4/4) -- `node tests/phase13/service-behaviour.test.cjs` -> **pass** (7/7) -- `node tests/phase14/service-behaviour.test.cjs` -> **pass** (5/5) -- `node tests/phase15/service-behaviour.test.cjs` -> **pass** (5/5) -- `npm run lint` -> **warnings only** (pre-existing `react-hooks/exhaustive-deps` warnings) - -## Latest update (2026-03-14 — Phase 19 endpoint consistency slice) - -- Continued on branch: - - `TASK22057-phase17-hardening-closeout` -- Delivered a small additional consistency-only endpoint slice across: - - `pages/api/endpoint/createwatchedcases_api.js` - - `pages/api/endpoint/getappealtypes_api.js` - - `pages/api/endpoint/getdnslist_api.js` -- Scope delivered: - - added required early 400 handling for malformed/missing `@odata.bind` values in `createwatchedcases_api` - - removed noisy query logging in `getappealtypes_api` and `getdnslist_api` - - preserved response-shape/signature contracts -- Added focused tests: - - `tests/phase19/service-behaviour.test.cjs` (5/5 passing) - -### Validation snapshot (Phase 19) - -- `node tests/phase6/service-parity.test.cjs` -> **pass** -- `node tests/phase6/service-behaviour.test.cjs` -> **pass** (8/8) -- `node tests/phase7/service-behaviour.test.cjs` -> **pass** (12/12) -- `node tests/phase8/service-behaviour.test.cjs` -> **pass** (5/5) -- `node tests/phase9/service-behaviour.test.cjs` -> **pass** (5/5) -- `node tests/phase10/service-behaviour.test.cjs` -> **pass** (5/5) -- `node tests/phase11/service-behaviour.test.cjs` -> **pass** (4/4) -- `node tests/phase12/service-behaviour.test.cjs` -> **pass** (4/4) -- `node tests/phase13/service-behaviour.test.cjs` -> **pass** (7/7) -- `node tests/phase14/service-behaviour.test.cjs` -> **pass** (9/9) -- `node tests/phase15/service-behaviour.test.cjs` -> **pass** (5/5) -- `node tests/phase16/service-behaviour.test.cjs` -> **pass** (4/4) -- `node tests/phase17/service-behaviour.test.cjs` -> **pass** (6/6) -- `node tests/phase18/service-behaviour.test.cjs` -> **pass** (8/8) -- `node tests/phase19/service-behaviour.test.cjs` -> **pass** (5/5) -- `npm run lint` -> **warnings only** (pre-existing `react-hooks/exhaustive-deps` warnings) - -## Latest update (2026-03-14 — Phase 20 endpoint consistency slice) - -- Continued on branch: - - `TASK22057-phase17-hardening-closeout` -- Delivered a small additional consistency-only endpoint slice across: - - `pages/api/endpoint/getbasicdnssearch_api.js` - - `pages/api/endpoint/getbasicdnsurlsearch_api.js` - - `pages/api/endpoint/getbasicsearchdetailspaged_api.js` -- Scope delivered: - - removed noisy query logging in `getbasicdnssearch_api` - - standardized missing/empty `searchString` handling in `getbasicdnsurlsearch_api` with early 400 - - standardized missing required input handling in `getbasicsearchdetailspaged_api` (`appealTypeName`, `primaryIdAttribute`, `incidentID`) with early 400 - - preserved response-shape/signature contracts -- Added focused tests: - - `tests/phase20/service-behaviour.test.cjs` (5/5 passing) - -### Validation snapshot (Phase 20) - -- `node tests/phase6/service-parity.test.cjs` -> **pass** -- `node tests/phase6/service-behaviour.test.cjs` -> **pass** (8/8) -- `node tests/phase7/service-behaviour.test.cjs` -> **pass** (12/12) -- `node tests/phase8/service-behaviour.test.cjs` -> **pass** (5/5) -- `node tests/phase9/service-behaviour.test.cjs` -> **pass** (5/5) -- `node tests/phase10/service-behaviour.test.cjs` -> **pass** (5/5) -- `node tests/phase11/service-behaviour.test.cjs` -> **pass** (4/4) -- `node tests/phase12/service-behaviour.test.cjs` -> **pass** (4/4) -- `node tests/phase13/service-behaviour.test.cjs` -> **pass** (7/7) -- `node tests/phase14/service-behaviour.test.cjs` -> **pass** (9/9) -- `node tests/phase15/service-behaviour.test.cjs` -> **pass** (5/5) -- `node tests/phase16/service-behaviour.test.cjs` -> **pass** (4/4) -- `node tests/phase17/service-behaviour.test.cjs` -> **pass** (6/6) -- `node tests/phase18/service-behaviour.test.cjs` -> **pass** (8/8) -- `node tests/phase19/service-behaviour.test.cjs` -> **pass** (5/5) -- `node tests/phase20/service-behaviour.test.cjs` -> **pass** (5/5) -- `npm run lint` -> **warnings only** (pre-existing `react-hooks/exhaustive-deps` warnings) - -### Manual HTTP snapshot (Phase 15) - -- Dev server run on `http://localhost:3002`. -- Negative-path checks: - - `POST /api/file/upload` missing hash -> **400** - - `POST /api/file/upload?hash=wrong` -> **400** - - `POST /api/file/uploadsinglefile` missing hash -> **400** - - `POST /api/file/uploadsinglefile?hash=wrong` -> **400** - - `GET /api/file/createappealcompletemessage_api?container=c1&tempcaseref=t1` missing hash -> **400** - - `GET /api/file/createappealcompletemessage_api?container=c1&tempcaseref=t1&hash=wrong` -> **400** - - `GET /api/file/createappealcompletemessage_api?container=c1` missing required params/hash -> **400** - - `GET /api/file/setupcontainer?ident=c1` missing hash -> **400** - - `GET /api/file/setupcontainer?ident=c1&hash=wrong` -> **400** - - `GET /api/file/setupcontainer?hash=` missing required `ident` -> **400** -- Valid-hash spot-check: - - `GET /api/file/setupcontainer?ident=c1&hash=` -> **200** - -### Rollback plan (Phase 15) - -1. Revert these files: - - `pages/api/file/upload.js` - - `pages/api/file/uploadsinglefile.js` - - `pages/api/file/createappealcompletemessage_api.js` - - `pages/api/file/setupcontainer.js` - - `tests/phase15/service-behaviour.test.cjs` -2. Re-run phase6–phase15 tests and lint to confirm parity. - -## Latest update (2026-03-13 — Phase 16 file-proxy consistency slice) - -- Continued on branch: - - `TASK22028-phase15-hardening-slice` -- Delivered a small consistency-only hardening slice across 3 sensitive file proxy handlers: - - `pages/api/file/getbloblistproxy.js` - - `pages/api/file/getrepsblobproxy.js` - - `pages/api/file/getawaitingsubmissionfromblobproxy.js` -- Scope delivered: - - removed unused imports/constants in touched handlers to reduce noisy/unsafe dead code - - standardized required input checks using shared local `hasValue` pattern - - preserved response shape/signature/status behavior contracts -- Added focused tests: - - `tests/phase16/service-behaviour.test.cjs` - - negative-path checks for missing required container/casefolder inputs - - one valid-input happy-path contract check for `getbloblistproxy` (200 + passthrough shape) - -### Validation snapshot (Phase 16) - -- `node tests/phase6/service-parity.test.cjs` -> **pass** -- `node tests/phase6/service-behaviour.test.cjs` -> **pass** (8/8) -- `node tests/phase7/service-behaviour.test.cjs` -> **pass** (10/10) -- `node tests/phase8/service-behaviour.test.cjs` -> **pass** (5/5) -- `node tests/phase9/service-behaviour.test.cjs` -> **pass** (5/5) -- `node tests/phase10/service-behaviour.test.cjs` -> **pass** (5/5) -- `node tests/phase11/service-behaviour.test.cjs` -> **pass** (4/4) -- `node tests/phase12/service-behaviour.test.cjs` -> **pass** (4/4) -- `node tests/phase13/service-behaviour.test.cjs` -> **pass** (7/7) -- `node tests/phase14/service-behaviour.test.cjs` -> **pass** (5/5) -- `node tests/phase15/service-behaviour.test.cjs` -> **pass** (5/5) -- `node tests/phase16/service-behaviour.test.cjs` -> **pass** (4/4) -- `npm run lint` -> **warnings only** (pre-existing `react-hooks/exhaustive-deps` warnings) - -## Latest update (2026-03-19 — TASK22168 endpoint account contract consistency slice) - -- New branch created from `origin/SIPS-Development` with required work item prefix: - - `TASK22168-endpoint-account-contract-consistency` -- Delivered next coherent low-risk `pages/api/endpoint/**` slice after TASK22109 across: - - `pages/api/endpoint/getaccounts_api.js` - - `pages/api/endpoint/getemailaccountcheck_api.js` - - `pages/api/endpoint/getpreferredlanguage_api.js` -- Scope delivered: - - removed dead/noisy code in touched handlers (unused imports and commented debug remnants) - - standardized structured negative-path handling for: - - missing required `emailAddress` - - catch/failure paths - - preserved success response contracts by returning unchanged upstream `data` -- Added focused phase21 endpoint contract coverage: - - `tests/phase21/endpoint-handler-contract.test.cjs` - - extended `tests/phase21/api-contract-slice1.test.cjs` runner - -### Validation snapshot (TASK22168) - -- `node tests/phase21/api-contract-slice1.test.cjs` -> **pass** - - helper: 4/4 - - file-handler: 11/11 - - email-handler: 12/12 - - endpoint-handler: 7/7 -- `npm run lint` -> **warnings only** (pre-existing `react-hooks/exhaustive-deps` warnings) - -### Risks + mitigations (TASK22168) - -- Risk: endpoint contract drift in success payloads. - - Mitigation: success responses kept as upstream `data` payload via `respondSuccess`. -- Risk: over-broad behavior change in account/login adjacent APIs. - - Mitigation: scoped to 3 low-risk handlers only; no auth/session/security flow changes. -- Risk: regression in negative-path status/shape expectations. - - Mitigation: added explicit phase21 missing-input and catch-path assertions for each touched endpoint. - -### Rollback plan (TASK22168) - -1. Revert endpoint files: - - `pages/api/endpoint/getaccounts_api.js` - - `pages/api/endpoint/getemailaccountcheck_api.js` - - `pages/api/endpoint/getpreferredlanguage_api.js` -2. Revert phase21 test updates: - - `tests/phase21/endpoint-handler-contract.test.cjs` - - `tests/phase21/api-contract-slice1.test.cjs` -3. Re-run: - - `node tests/phase21/api-contract-slice1.test.cjs` - - `npm run lint` - -## Latest update (2026-03-19 — TASK22168 Bundle C extension on same branch) - -- Continued same branch with user-approved larger bundle: - - `TASK22168-endpoint-account-contract-consistency` -- Added contract-consistency coverage for login/portal/account-adjacent endpoints: - - `pages/api/endpoint/getlogin_api.js` - - `pages/api/endpoint/getportallogin_api.js` - - `pages/api/endpoint/getportalloginproxy_api.js` - - `pages/api/endpoint/getpersonalaccount_api.js` -- Scope delivered: - - removed dead imports/commented debug/noisy logging remnants - - standardized structured 400 errors for required-input negative paths and catch/failure paths - - preserved success payload contracts via `respondSuccess` pass-through -- Phase21 endpoint suite expanded in: - - `tests/phase21/endpoint-handler-contract.test.cjs` - - test count grew from 7 to 18 for endpoint handler coverage - -### Validation snapshot (TASK22168 Bundle C) - -- `node tests/phase21/api-contract-slice1.test.cjs` -> **pass** - - helper: 4/4 - - file-handler: 11/11 - - email-handler: 12/12 - - endpoint-handler: 18/18 -- `npm run lint` -> **warnings only** (pre-existing `react-hooks/exhaustive-deps` warnings) - -### Risks + mitigations (TASK22168 Bundle C) - -- Risk: contract drift from broad endpoint touch surface. - - Mitigation: constrained to login/account adjacency group only and preserved success pass-through behavior. -- Risk: hash-path behavior regression in `getportallogin_api`. - - Mitigation: explicit tests for missing hash, invalid hash, and catch path. -- Risk: inconsistent required-input behavior across adjacent handlers. - - Mitigation: standardized explicit required-input envelopes in all four newly touched handlers. - -### Rollback plan (TASK22168 Bundle C) - -1. Revert endpoint files: - - `pages/api/endpoint/getlogin_api.js` - - `pages/api/endpoint/getportallogin_api.js` - - `pages/api/endpoint/getportalloginproxy_api.js` - - `pages/api/endpoint/getpersonalaccount_api.js` -2. Revert endpoint contract test updates: - - `tests/phase21/endpoint-handler-contract.test.cjs` -3. Re-run: - - `node tests/phase21/api-contract-slice1.test.cjs` - - `npm run lint` - -### Manual HTTP checks (Phase 16) - -- Dev server on `http://localhost:3002`. -- Negative-path checks: - - `/api/file/getbloblistproxy?casefolderID=case-1` -> **400** - - `/api/file/getbloblistproxy?container=c1` -> **400** - - `/api/file/getrepsblobproxy` -> **400** - - `/api/file/getawaitingsubmissionfromblobproxy` -> **400** -- Feasible valid-input spot-check: - - `/api/file/getbloblistproxy?container=c1&casefolderID=case-1` -> **400** (expected downstream/local dependency behavior; input guard passed) - -### Rollback plan (Phase 16) - -1. Revert commit `c196edb` or files: - - `pages/api/file/getbloblistproxy.js` - - `pages/api/file/getrepsblobproxy.js` - - `pages/api/file/getawaitingsubmissionfromblobproxy.js` - - `tests/phase16/service-behaviour.test.cjs` -2. Re-run phase6–phase16 tests and lint. - -## Latest update (2026-03-13 — signer allow-list follow-up) - -- Branch: `TASK22028-phase15-hardening-slice` -- Fix applied: - - added `/api/file/deleteblobcase` to signer endpoint allow-list in `pages/api/endpoint/gethash_api.js` -- Test update: - - extended `tests/phase14/service-behaviour.test.cjs` with deleteblobcase allow-list coverage - -### Validation snapshot (follow-up) - -- `node tests/phase14/service-behaviour.test.cjs` -> **pass** (6/6) -- `node tests/phase7/service-behaviour.test.cjs` -> **pass** (10/10) -- `npm run lint` -> **warnings only** (pre-existing) - -## Latest update (2026-03-13 — signer delete-flow follow-up) - -- Branch: `TASK22028-phase15-hardening-slice` -- Extended signer allow-list and browser signer usage for additional delete flows: - - `deleteWatchedCases` - - `deleteMyRepresentations` - - `deleteAwaitingSubmissionsFromBlob` - - `deleteMyRepresentationsFromBlob` - -### Validation snapshot (delete-flow follow-up) - -- `node tests/phase7/service-behaviour.test.cjs` -> **pass** (12/12) -- `node tests/phase14/service-behaviour.test.cjs` -> **pass** (9/9) -- `npm run lint` -> **warnings only** (pre-existing) - -## Latest update (2026-03-13 — myportal + i18n follow-up) - -- Branch: `TASK22028-phase15-hardening-slice` -- Delivered follow-up fixes: - - myportal representation delete calls now use `caseRef` in top-three and view-all flows - - missing `myportal` namespace added for `/newappeal/[appealtypes]` in `i18n.js` - -### Validation snapshot (myportal + i18n follow-up) - -- `node tests/phase7/service-behaviour.test.cjs` -> **pass** (12/12) -- `npm run lint` -> **warnings only** (pre-existing) - -## Outstanding risks / gaps - -- Navigation regressions across EN/CY + route query combinations. -- Drift between rewrite config and component-level locale path logic. -- Deployment ambiguity due to multiple CI/CD artifacts (Azure pipeline, Jenkins, Docker) with unclear active source of truth. -- Security posture variability where hash checks are bypassed/commented in selected handlers. - -## Latest update (2026-03-13 — Phase 7 post-Phase-6 hardening) - -- New branch created from `origin/SIPS-Development` with required work item prefix: - - `TASK21988a-phase7-postphase6-hardening` -- Fixed known pre-existing SSR serialization issue on search results route: - - `pages/searchresults.js` - - updated SSR dispatch fallback from `setSearch(query.q)` to `setSearch(query?.q || "")` - - result: `/searchresults` and `/cy/searchresults` now return 200 in local smoke checks (no 500 observed in this run). -- Added expanded behavioural coverage for remaining direct-service domains: - - new test file: `tests/phase7/service-behaviour.test.cjs` - - includes document, portal, account, notify, integration behavioural checks - - includes negative-path assertions for relay/hash/token-sensitive behaviors where feasible: - - hashed URL append checks (`hashAPIPath`) - - error handling contracts (undefined/error string/rethrow depending on existing function contract) - -### Validation snapshot (Phase 7) - -- `node tests/phase6/service-parity.test.cjs` -> **pass** -- `node tests/phase6/service-behaviour.test.cjs` -> **pass** (8/8) -- `node tests/phase7/service-behaviour.test.cjs` -> **pass** (10/10) -- `npm run lint` -> **warnings only** (pre-existing hook dependency warnings; no new lint errors) - -### Targeted smoke snapshot (local dev server) - -- Note: dev server auto-started on `http://localhost:3001` because port `3000` was in use. -- Search flow: - - `GET /searchresults` and `GET /cy/searchresults` -> **200** -- Case flow: - - `GET /case` and `GET /cy/case` -> **200** -- My Portal flow (negative-path): - - `GET /myportal` and `GET /cy/myportal` -> **307** redirect to `/auth/signin` -- Document flow (negative-path): - - `GET /api/file/getbloblistproxy?container=test&casefolderID=test` -> **400** -- Notify flow (negative-path): - - `POST /api/email/notify` with `{}` -> **400** diff --git a/memory-bank/refactor-plan-actions-index.md b/memory-bank/refactor-plan-actions-index.md deleted file mode 100644 index 604735f0..00000000 --- a/memory-bank/refactor-plan-actions-index.md +++ /dev/null @@ -1,1059 +0,0 @@ -# Refactor Plan — Priority 1 (`actions/index.js` split) - -Last updated: 2026-03-13 - -## Handover note (2026-03-13) - -- Import-migration wave from `actions` barrel to focused modules has been checked in and completed via PR. -- Next chunk will be delivered from a **new branch** and should start at legacy decomposition. - -### Next branch kickoff scope (Phase 5) - -Primary objective: split `actions/services/legacyActionsService.js` into smaller direct implementations while preserving function signatures. - -Recommended first slice: - -1. Extract reference/search internals from `legacyActionsService.js` into dedicated modules. -2. Keep `actions/services/*` exports stable and route through new direct implementations. -3. Add focused parity checks per extracted function group (inputs, headers, hash behavior, return shapes). - -Then continue with: - -4. Portal/document extraction in small batches. -5. Remove dead wrappers from `legacyActionsService.js` once call paths are fully migrated. - -### Phase 5 slice roadmap (completed) - -Status key: `[x] done`, `[ ] pending` - -1. `[x]` Search + reference direct extraction - - `searchDirectService.js`, `referenceDataDirectService.js` - - `searchService.js` / `referenceDataService.js` re-pointed -2. `[x]` Document direct extraction - - create `documentDirectService.js` - - re-point `documentService.js` - - parity checks: blob paths/hash behavior/return shapes -3. `[x]` Portal direct extraction - - create `portalDirectService.js` - - re-point `portalService.js` - - parity checks: watched-case and completion-message flows -4. `[x]` Account + case direct extraction - - create `accountDirectService.js`, `caseDirectService.js` - - re-point grouped services -5. `[x]` Notify + integration + admin direct extraction - - create `notifyDirectService.js`, `integrationDirectService.js`, `adminDirectService.js` -6. `[x]` Legacy slim-down pass - - remove dead wrappers from `legacyActionsService.js` - - keep only temporary compatibility exports still required -7. `[x]` Final cleanup + validation pass - - grep checks for remaining `./legacyActionsService` imports - - lint/manual smoke checks - -### Phase 5 completion snapshot (2026-03-13) - -- All grouped service modules now route through focused direct modules under `actions/services/*DirectService.js`. -- `actions/services/legacyActionsService.js` has been removed. -- Verification completed: - - `actions/services` scan returns zero `./legacyActionsService` imports. - - `npm run lint` completes with warnings only. - - `npm run build` completes successfully. - -### Next phase kickoff recommendation - -Focus on post-split hardening and cleanup: - -1. Add parity-focused tests for extracted direct services and `actions/services/index.js` export stability. -2. Consolidate repeated axios/error-handling patterns into shared clients/utilities where safe. -3. Reduce verbose debug logging in direct services (especially account/case/document paths) with redaction discipline. -4. Run targeted manual smoke matrix for search/case/myportal/document/notify with EN/CY parity checks. - -### Phase 6 completion snapshot (2026-03-13) - -Status key: `[x] done`, `[ ] pending` - -1. `[x]` Add parity-focused tests for extracted services and barrel stability - - `tests/phase6/service-parity.test.cjs` - - validates grouped/direct service export parity - - validates `actions/services/index.js` export stability -2. `[x]` Reduce repeated axios/error-handling patterns safely - - added shared helper: `actions/services/httpServiceUtils.js` - - adopted in selected direct modules without signature/return-shape changes -3. `[x]` Logging cleanup in sensitive direct-service flows - - removed noisy debug logs from search/document/portal/case/admin direct services -4. `[x]` Add focused behavioural contract tests in current phase - - `tests/phase6/service-behaviour.test.cjs` - - success/error contract checks with mocked axios/logger (8/8 passing) -5. `[x]` Run targeted validation/smoke checks - - parity test: pass - - behavioural test: pass - - manual smoke matrix executed (search/case/myportal/document/notify, EN/CY + negative paths) - -Notes: - -- Known pre-existing caveat during smoke checks: - - `/searchresults` and `/cy/searchresults` return 500 in local dev due SSR serialization issue (`initialState.search.searchString` undefined). - - treated as existing issue, not introduced by this refactor phase. - -### Future requirements / next-phase backlog (post-Phase-6) - -1. Investigate and fix `/searchresults` SSR serialization issue (EN/CY parity). -2. Expand behavioural service tests to remaining domains: - - document - - portal - - account - - notify - - integration -3. Add focused negative-path tests for token/hash/relay-sensitive handlers. -4. Continue small-batch hardening with reversible commits and parity checks per batch. -5. Prepare PR evidence bundle for each increment: - - lint + test commands - - behavioural/parity test outputs - - manual EN/CY + negative-path smoke matrix - -### Phase 7 completion snapshot (2026-03-13) - -Status key: `[x] done`, `[ ] pending` - -1. `[x]` Create new branch from `origin/SIPS-Development` with required work item prefix - - branch: `TASK21988a-phase7-postphase6-hardening` -2. `[x]` Fix pre-existing `/searchresults` SSR serialization issue with EN/CY parity - - updated `pages/searchresults.js`: - - `setSearch(query.q)` -> `setSearch(query?.q || "")` -3. `[x]` Expand behavioural tests to remaining service domains - - added `tests/phase7/service-behaviour.test.cjs` - - coverage includes: document, portal, account, notify, integration -4. `[x]` Add feasible negative-path tests for token/hash/relay-sensitive flows - - validated hashed path composition (e.g., `hashAPIPath` usage) - - validated existing function error contracts (undefined/error string/rethrow) -5. `[x]` Execute validation bundle - - `node tests/phase6/service-parity.test.cjs` -> pass - - `node tests/phase6/service-behaviour.test.cjs` -> pass (8/8) - - `node tests/phase7/service-behaviour.test.cjs` -> pass (10/10) - - `npm run lint` -> warnings only (no new errors) -6. `[x]` Execute targeted manual smoke matrix (EN/CY + negative paths) - - local server on `localhost:3001` (3000 occupied) - - `/searchresults`, `/cy/searchresults` -> 200 - - `/case`, `/cy/case` -> 200 - - `/myportal`, `/cy/myportal` -> 307 -> `/auth/signin` - - `/api/file/getbloblistproxy?container=test&casefolderID=test` -> 400 - - `POST /api/email/notify` with `{}` -> 400 - -### Phase 7 rollback notes - -- Revert `pages/searchresults.js` fallback change if search behaviour regresses unexpectedly. -- Remove `tests/phase7/service-behaviour.test.cjs` if test scope needs to be rolled back. -- Reset branch to pre-Phase-7 commit if full rollback required. - -### Phase 8 completion snapshot (2026-03-13) - -Status key: `[x] done`, `[ ] pending` - -1. `[x]` Create new branch from `origin/SIPS-Development` with required work item prefix - - branch: `TASK22017-phase8-hardening-slice` -2. `[x]` Re-enable/enforce hash validation in 4 sensitive target handlers - - `pages/api/file/deleteblobcase.js` - - `pages/api/file/deleteblobrep.js` - - `pages/api/file/createappealcompletemessage_api.js` - - `pages/api/endpoint/getportallogin_api.js` -3. `[x]` Standardize negative-path behavior for invalid/missing hash and required keys - - added early 400 guards for missing required query params where applicable - - preserved response-shape contracts/signatures -4. `[x]` Improve logging discipline in sensitive flow - - removed noisy direct console output in `createappealcompletemessage_api` - - routed updated error path logging via `consoleLogger` -5. `[x]` Keep caller behavior compatible after hash re-enforcement - - `actions/services/documentDirectService.js` now appends hash for: - - `deleteblobcase` - - `deleteblobrep` - - `actions/services/portalDirectService.js` now appends hash for: - - `createappealcompletemessage_api` (existing hash-path contract retained) -6. `[x]` Add focused Phase 8 tests - - added `tests/phase8/service-behaviour.test.cjs` - - includes negative-path coverage for all 4 target handlers - - includes one valid-hash happy-path contract check (`getportallogin_api`) via mocks -7. `[x]` Execute validation bundle - - `node tests/phase6/service-parity.test.cjs` -> pass - - `node tests/phase6/service-behaviour.test.cjs` -> pass (8/8) - - `node tests/phase7/service-behaviour.test.cjs` -> pass (10/10) - - `node tests/phase8/service-behaviour.test.cjs` -> pass (5/5) - - `npm run lint` -> warnings only (pre-existing react-hooks dependency warnings) -8. `[x]` Execute manual HTTP negative-path matrix + feasible happy-path spot-check - - invalid/missing hash across 4 target handlers -> 400 - - missing required params where tested -> 400 - - valid-hash `getportallogin_api` spot-check returned 400 in local env due upstream relay/CRM dependency - -### Phase 8 rollback notes - -- Revert these files to rollback the full hardening slice: - - `pages/api/file/deleteblobcase.js` - - `pages/api/file/deleteblobrep.js` - - `pages/api/file/createappealcompletemessage_api.js` - - `pages/api/endpoint/getportallogin_api.js` - - `actions/services/documentDirectService.js` - - `actions/services/portalDirectService.js` - - `tests/phase8/service-behaviour.test.cjs` -- Re-run phase6/phase7 baseline tests and lint after rollback to confirm parity. - -### Phase 9 completion snapshot (2026-03-13) - -Status key: `[x] done`, `[ ] pending` - -1. `[x]` Create new branch from `origin/SIPS-Development` with required work item prefix - - branch: `TASK22019-phase-9-hardening` -2. `[x]` Re-enable/enforce hash validation in 4 additional sensitive file handlers - - `pages/api/file/createrepcompletemessage_api.js` - - `pages/api/file/upload.js` - - `pages/api/file/uploadsinglefile.js` - - `pages/api/file/setupcontainer.js` -3. `[x]` Standardize negative-path behavior for invalid/missing hash and key params - - added early 400 handling for missing required query/body values where applicable -4. `[x]` Improve logging discipline in sensitive paths - - removed noisy direct console logging in touched handlers -5. `[x]` Keep caller behavior compatible after hash re-enforcement - - `actions/services/portalDirectService.js` - - `sendRepCompleteMessage` now appends hash - - `actions/services/documentDirectService.js` - - upload-related calls now append hash -6. `[x]` Add focused Phase 9 tests - - added `tests/phase9/service-behaviour.test.cjs` - - negative-path tests for all 4 selected handlers -7. `[x]` Execute validation bundle - - `node tests/phase6/service-parity.test.cjs` -> pass - - `node tests/phase6/service-behaviour.test.cjs` -> pass (8/8) - - `node tests/phase7/service-behaviour.test.cjs` -> pass (10/10) - - `node tests/phase8/service-behaviour.test.cjs` -> pass (5/5) - - `node tests/phase9/service-behaviour.test.cjs` -> pass (5/5) - - `npm run lint` -> warnings only (no new lint errors) -8. `[x]` Execute manual HTTP negative-path matrix - - missing/invalid hash checks across selected handlers -> 400 - - missing key params where tested -> 400 -9. `[x]` Valid-hash HTTP happy-path spot-check - - `POST /api/file/uploadsinglefile?hash=` -> 200 (hash generated from `.env.local` key) - -### Phase 9 rollback notes - -- Revert these files to rollback the full hardening slice: - - `pages/api/file/createrepcompletemessage_api.js` - - `pages/api/file/upload.js` - - `pages/api/file/uploadsinglefile.js` - - `pages/api/file/setupcontainer.js` - - `actions/services/portalDirectService.js` - - `actions/services/documentDirectService.js` - - `tests/phase9/service-behaviour.test.cjs` -- Re-run phase6/phase7/phase8/phase9 baseline tests and lint after rollback to confirm parity. - -### Phase 10 completion snapshot (2026-03-13) - -Status key: `[x] done`, `[ ] pending` - -1. `[x]` Continue connected hardening slices on same branch - - branch: `TASK22019-phase-9-hardening` -2. `[x]` Re-enable/standardize hash + param guard handling in 4 additional file retrieval handlers - - `pages/api/file/getawaitingsubmissionfromblob.js` - - `pages/api/file/getprogressobjblob.js` - - `pages/api/file/getbloblist.js` - - `pages/api/file/getrepsblob.js` -3. `[x]` Standardize negative-path behavior - - added explicit early 400 for missing required query/hash values - - standardized early 400 for hash mismatch -4. `[x]` Improve logging discipline in touched handlers - - removed old commented debug traces -5. `[x]` Add focused Phase 10 tests - - added `tests/phase10/service-behaviour.test.cjs` - - includes negative-path tests for all 4 handlers -6. `[x]` Execute validation bundle - - `node tests/phase6/service-parity.test.cjs` -> pass - - `node tests/phase6/service-behaviour.test.cjs` -> pass (8/8) - - `node tests/phase7/service-behaviour.test.cjs` -> pass (10/10) - - `node tests/phase8/service-behaviour.test.cjs` -> pass (5/5) - - `node tests/phase9/service-behaviour.test.cjs` -> pass (5/5) - - `node tests/phase10/service-behaviour.test.cjs` -> pass (5/5) - - `npm run lint` -> warnings only (no new lint errors) -7. `[x]` Execute manual HTTP negative-path matrix + valid-hash spot-check - - missing hash across selected handlers -> 400 - - valid hash `getbloblist` spot-check -> 500 (downstream/local dependency) - -### Phase 10 rollback notes - -- Revert these files to rollback the full hardening slice: - - `pages/api/file/getawaitingsubmissionfromblob.js` - - `pages/api/file/getprogressobjblob.js` - - `pages/api/file/getbloblist.js` - - `pages/api/file/getrepsblob.js` - - `tests/phase10/service-behaviour.test.cjs` -- Re-run phase6/phase7/phase8/phase9/phase10 baseline tests and lint after rollback to confirm parity. - -### Phase 11 completion snapshot (2026-03-13) - -Status key: `[x] done`, `[ ] pending` - -1. `[x]` Continue connected hardening slices on same branch - - branch: `TASK22019-phase-9-hardening` -2. `[x]` Re-enable/standardize hash + param guard handling in additional sensitive handlers - - `pages/api/file/getbloblist.js` - - `pages/api/file/deleteblob.js` - - `pages/api/file/deleteawaitingsubmissionfromblob.js` -3. `[x]` Standardize negative-path behavior - - added explicit early 400 for missing required query/hash values - - standardized early 400 for hash mismatch -4. `[x]` Improve logging discipline in touched handlers - - removed old commented debug traces -5. `[x]` Add focused Phase 11 tests - - added `tests/phase11/service-behaviour.test.cjs` - - includes negative-path tests for selected handlers -6. `[x]` Execute validation bundle - - `node tests/phase6/service-parity.test.cjs` -> pass - - `node tests/phase6/service-behaviour.test.cjs` -> pass (8/8) - - `node tests/phase7/service-behaviour.test.cjs` -> pass (10/10) - - `node tests/phase8/service-behaviour.test.cjs` -> pass (5/5) - - `node tests/phase9/service-behaviour.test.cjs` -> pass (5/5) - - `node tests/phase10/service-behaviour.test.cjs` -> pass (5/5) - - `node tests/phase11/service-behaviour.test.cjs` -> pass (4/4) - - `npm run lint` -> warnings only (no new lint errors) -7. `[x]` Execute manual HTTP negative-path matrix + valid-hash spot-check - - missing/invalid hash across selected handlers -> 400 - - valid hash `getbloblist` spot-check -> 500 (downstream/local dependency) - -### Phase 11 rollback notes - -- Revert these files to rollback the full hardening slice: - - `pages/api/file/getbloblist.js` - - `pages/api/file/deleteblob.js` - - `pages/api/file/deleteawaitingsubmissionfromblob.js` - - `tests/phase11/service-behaviour.test.cjs` -- Re-run phase6/phase7/phase8/phase9/phase10/phase11 baseline tests and lint after rollback to confirm parity. - -### Phase 12 completion snapshot (2026-03-13) - -Status key: `[x] done`, `[ ] pending` - -1. `[x]` Continue connected hardening slices on same branch - - branch: `TASK22019-phase-9-hardening` -2. `[x]` Re-enable/standardize hash + param guard handling in additional sensitive handlers - - `pages/api/file/downloadblob.js` - - `pages/api/file/getbloblistproxy.js` - - `pages/api/file/getrepsblobproxy.js` - - `pages/api/file/getawaitingsubmissionfromblobproxy.js` -3. `[x]` Standardize negative-path behavior - - added explicit early 400 for missing required query/hash values - - standardized early 400 for hash mismatch in `downloadblob` -4. `[x]` Add focused Phase 12 tests - - added `tests/phase12/service-behaviour.test.cjs` - - includes negative-path tests for selected handlers -5. `[x]` Execute validation bundle - - `node tests/phase6/service-parity.test.cjs` -> pass - - `node tests/phase6/service-behaviour.test.cjs` -> pass (8/8) - - `node tests/phase7/service-behaviour.test.cjs` -> pass (10/10) - - `node tests/phase8/service-behaviour.test.cjs` -> pass (5/5) - - `node tests/phase9/service-behaviour.test.cjs` -> pass (5/5) - - `node tests/phase10/service-behaviour.test.cjs` -> pass (5/5) - - `node tests/phase11/service-behaviour.test.cjs` -> pass (4/4) - - `node tests/phase12/service-behaviour.test.cjs` -> pass (4/4) - - `npm run lint` -> warnings only (no new lint errors) -6. `[x]` Execute manual HTTP negative-path matrix + valid-hash spot-check - - missing/invalid inputs across selected handlers -> 400 - - valid hash `downloadblob` spot-check -> 500 (downstream/local dependency) - -### Phase 12 rollback notes - -- Revert these files to rollback the full hardening slice: - - `pages/api/file/downloadblob.js` - - `pages/api/file/getbloblistproxy.js` - - `pages/api/file/getrepsblobproxy.js` - - `pages/api/file/getawaitingsubmissionfromblobproxy.js` - - `tests/phase12/service-behaviour.test.cjs` -- Re-run phase6/phase7/phase8/phase9/phase10/phase11/phase12 baseline tests and lint after rollback to confirm parity. - -### Phase 13 completion snapshot (2026-03-13) - -Status key: `[x] done`, `[ ] pending` - -1. `[x]` Continue connected hardening slices on same branch - - branch: `TASK22019-phase-9-hardening` -2. `[x]` Re-enable/standardize hash + param guard handling in additional sensitive handlers - - `pages/api/file/deleteblobcase.js` - - `pages/api/file/deleteblobrep.js` - - `pages/api/file/createcaseinvolvement_api.js` - - `pages/api/file/createrepinvolvement_api.js` -3. `[x]` Standardize negative-path behavior - - added explicit early 400 for missing required query/hash/body values - - standardized early 400 for hash mismatch in delete handlers -4. `[x]` Improve logging discipline in touched handlers - - removed noisy body/query logging in involvement handlers -5. `[x]` Add focused Phase 13 tests - - added `tests/phase13/service-behaviour.test.cjs` - - includes negative-path tests and valid-input mocked happy paths -6. `[x]` Execute validation bundle - - `node tests/phase6/service-parity.test.cjs` -> pass - - `node tests/phase6/service-behaviour.test.cjs` -> pass (8/8) - - `node tests/phase7/service-behaviour.test.cjs` -> pass (10/10) - - `node tests/phase8/service-behaviour.test.cjs` -> pass (5/5) - - `node tests/phase9/service-behaviour.test.cjs` -> pass (5/5) - - `node tests/phase10/service-behaviour.test.cjs` -> pass (5/5) - - `node tests/phase11/service-behaviour.test.cjs` -> pass (4/4) - - `node tests/phase12/service-behaviour.test.cjs` -> pass (4/4) - - `node tests/phase13/service-behaviour.test.cjs` -> pass (7/7) - - `npm run lint` -> warnings only (no new lint errors) -7. `[x]` Execute manual HTTP negative-path matrix + valid-hash spot-check - - missing/invalid inputs across selected handlers -> 400 - - valid hash `deleteblobcase` spot-check -> 500 (downstream/local dependency) - -### Phase 13 rollback notes - -- Revert these files to rollback the full hardening slice: - - `pages/api/file/deleteblobcase.js` - - `pages/api/file/deleteblobrep.js` - - `pages/api/file/createcaseinvolvement_api.js` - - `pages/api/file/createrepinvolvement_api.js` - - `tests/phase13/service-behaviour.test.cjs` -- Re-run phase6/phase7/phase8/phase9/phase10/phase11/phase12/phase13 baseline tests and lint after rollback to confirm parity. - -### Phase 14 completion snapshot (2026-03-13) - -Status key: `[x] done`, `[ ] pending` - -1. `[x]` Diagnose authenticated browser journey runtime error - - traced to client-side `hashAPIPath` usage reading server-only `HASHKEY` -2. `[x]` Implement minimal reversible signing bridge - - added `pages/api/endpoint/gethash_api.js` - - session-gated with allow-listed API path prefixes -3. `[x]` Keep client/service contracts stable - - updated `documentDirectService` and `portalDirectService` to request hash from signer endpoint - - kept server-side fallback hashing only when env key exists -4. `[x]` Add focused phase-14 tests - - added `tests/phase14/service-behaviour.test.cjs` - - covers 400/401 negative paths and authenticated happy path -5. `[x]` Execute validation bundle - - phase6–phase14 test set all pass - - lint warnings only (pre-existing) - -### Phase 14 rollback notes - -- Revert these files to rollback the fix slice: - - `pages/api/endpoint/gethash_api.js` - - `actions/services/documentDirectService.js` - - `actions/services/portalDirectService.js` - - `tests/phase14/service-behaviour.test.cjs` -- Re-run phase6–phase14 tests + lint after rollback. - -### Phase 14 closeout follow-up snapshot (2026-03-13) - -Status key: `[x] done`, `[ ] pending` - -1. `[x]` Expand signer usage to remaining browser-sensitive hashed call in account domain - - `actions/services/accountDirectService.js` - - `getPortalLogin` now requests hash from authenticated signer endpoint -2. `[x]` Extend signer allow-list minimally for required route - - `pages/api/endpoint/gethash_api.js` - - added `/api/endpoint/getportallogin_api` only -3. `[x]` Preserve and verify behavioural contract coverage - - `tests/phase7/service-behaviour.test.cjs` updated for signer flow - - `tests/phase14/service-behaviour.test.cjs` extended with allow-list path test -4. `[x]` Apply runtime-discovered contract alignment fixes (minimal/reversible) - - `pages/api/file/getrepsblob.js` - - removed unnecessary `casefolderID` requirement to match endpoint contract - - `components/elements/index.js` - - restored missing `updateLinks` import for Quill path -5. `[x]` Re-run required validation - - phase6 parity + behaviour -> pass - - phase7/8/9/10/11/12/13/14 behaviour -> pass - - lint -> warnings only (pre-existing) -6. `[x]` Push branch for review continuity - - `TASK22019-phase-9-hardening` pushed to origin - -### Phase 14 closeout follow-up rollback notes - -- Revert `6094874` to remove portal-login signer migration and tests. -- Revert `b8fa514` to remove getrepsblob contract-alignment + Quill import fix. -- Re-run phase6–phase14 tests and lint after rollback. - -### Phase 15 completion snapshot (2026-03-13) - -Status key: `[x] done`, `[ ] pending` - -1. `[x]` Create new branch from `origin/SIPS-Development` with required work item prefix - - branch: `TASK22028-phase15-hardening-slice` -2. `[x]` Apply minimal consistency-only hardening in 4 additional sensitive handlers - - `pages/api/file/upload.js` - - `pages/api/file/uploadsinglefile.js` - - `pages/api/file/createappealcompletemessage_api.js` - - `pages/api/file/setupcontainer.js` -3. `[x]` Standardize negative-path behavior - - explicit early 400 for missing/invalid hash in selected handlers - - explicit missing required-input checks where route contract requires them - - preserved response-shape contracts and function signatures -4. `[x]` Add focused Phase 15 tests - - added `tests/phase15/service-behaviour.test.cjs` - - includes negative-path tests for missing/invalid hash + required-input checks - - includes one valid-hash mocked happy-path response-shape check -5. `[x]` Execute required validation bundle - - phase6 parity + phase6–phase14 behaviour tests -> pass - - phase15 behaviour tests -> pass - - lint -> warnings only (pre-existing) -6. `[x]` Execute targeted manual checks - - missing/invalid hash across selected handlers -> 400 - - missing required params where applicable -> 400 - - valid-hash `setupcontainer` spot-check -> 200 - -### Phase 15 rollback notes - -- Revert these files to rollback the full hardening slice: - - `pages/api/file/upload.js` - - `pages/api/file/uploadsinglefile.js` - - `pages/api/file/createappealcompletemessage_api.js` - - `pages/api/file/setupcontainer.js` - - `tests/phase15/service-behaviour.test.cjs` -- Re-run phase6–phase15 baseline tests and lint after rollback to confirm parity. - -### Phase 16 completion snapshot (2026-03-13) - -Status key: `[x] done`, `[ ] pending` - -1. `[x]` Continue on current branch with separate commit for additional small slice - - branch: `TASK22028-phase15-hardening-slice` -2. `[x]` Apply minimal consistency hardening in 3 file proxy handlers - - `pages/api/file/getbloblistproxy.js` - - `pages/api/file/getrepsblobproxy.js` - - `pages/api/file/getawaitingsubmissionfromblobproxy.js` -3. `[x]` Standardize required-input guard pattern - - added local `hasValue` checks for required params - - removed unused/dead imports/constants in touched files -4. `[x]` Add focused Phase 16 tests - - added `tests/phase16/service-behaviour.test.cjs` - - missing-input negative-path checks + one valid-input contract check -5. `[x]` Execute validation bundle - - phase6 parity + phase6–phase16 behaviour tests pass - - lint warnings only (pre-existing) -6. `[x]` Execute manual checks - - missing required-input proxy calls -> 400 - -### Phase 16 rollback notes - -- Revert commit `c196edb` (or files): - - `pages/api/file/getbloblistproxy.js` - - `pages/api/file/getrepsblobproxy.js` - - `pages/api/file/getawaitingsubmissionfromblobproxy.js` - - `tests/phase16/service-behaviour.test.cjs` -- Re-run phase6–phase16 baseline tests and lint. - -### Follow-up completion snapshot (2026-03-13) - -1. `[x]` Address browser signer failure for delete-awaiting-submission path - - added signer allow-list entry: `/api/file/deleteblobcase` -2. `[x]` Add focused behavioural test coverage - - extended `tests/phase14/service-behaviour.test.cjs` -3. `[x]` Validate - - phase14 behaviour tests pass (6/6) - - phase7 behaviour tests pass (10/10) - - lint warnings only (pre-existing) - -### Follow-up rollback notes - -- Revert commit `49dd990` to undo allow-list/test follow-up. - -### Follow-up completion snapshot (2026-03-13 — additional delete flows) - -1. `[x]` Expand signer allow-list for required browser delete paths -2. `[x]` Move remaining delete service calls to signer-based hash retrieval -3. `[x]` Extend focused service/signer tests -4. `[x]` Validate - - phase7 behaviour tests pass (12/12) - - phase14 behaviour tests pass (9/9) - - lint warnings only (pre-existing) - -### Follow-up rollback notes (additional delete flows) - -- Revert the follow-up commit for this slice to restore prior hashing behavior. - -### Follow-up completion snapshot (2026-03-13 — myportal + i18n alignment) - -1. `[x]` Align myportal delete-representation calls to use `caseRef` -2. `[x]` Add missing i18n namespace mapping for `/newappeal/[appealtypes]` -3. `[x]` Validate - - phase7 behaviour tests pass (12/12) - - lint warnings only (pre-existing) - -### Follow-up rollback notes (myportal + i18n alignment) - -- Revert commit `d32d7d0` to restore prior myportal/i18n state. - -### Phase 17 closeout snapshot (2026-03-13) - -Status key: `[x] done`, `[ ] pending` - -1. `[x]` Create new branch from `origin/SIPS-Development` with required work item prefix - - branch: `TASK22057-phase17-hardening-closeout` -2. `[x]` Complete remaining consistency-only hardening targets in `pages/api/file/**` - - `pages/api/file/generatepdf.js` - - `pages/api/file/generateappealpdf.js` - - `pages/api/file/createappealcompletemessageproxy_api.js` -3. `[x]` Standardize negative-path behavior and logging discipline - - explicit early 400 guards for missing/invalid hash where applicable - - explicit early 400 guards for missing required params where applicable - - noisy direct logs removed from touched handlers - - response-shape/signature contracts preserved -4. `[x]` Add focused Phase 17 tests - - added `tests/phase17/service-behaviour.test.cjs` - - includes missing/invalid hash negative-path checks - - includes missing required-param checks - - includes valid-input happy-path check for proxy contract -5. `[x]` Execute required validation bundle - - phase6 parity + phase6–phase17 behaviour tests -> pass - - lint -> warnings only (pre-existing) -6. `[x]` Consistency scan for remaining `pages/api/**` - - no additional broad hash/400 consistency gaps identified in `pages/api/endpoint/**` during this pass - -### Phase 17 rollback notes - -- Revert these files to rollback the full closeout slice: - - `pages/api/file/generatepdf.js` - - `pages/api/file/generateappealpdf.js` - - `pages/api/file/createappealcompletemessageproxy_api.js` - - `tests/phase17/service-behaviour.test.cjs` -- Re-run phase6–phase17 baseline tests and lint after rollback to confirm parity. - -### Phase 18 additional consolidation slices snapshot (2026-03-14) - -Status key: `[x] done`, `[ ] pending` - -1. `[x]` Confirm requested scope expansion to implement all 3 additional slices -2. `[x]` Apply endpoint logging/input hygiene slice - - `pages/api/endpoint/deletewatchedcases_api.js` - - `pages/api/endpoint/getaccounts_api.js` - - `pages/api/endpoint/getbasicsearchpaged_api.js` - - `pages/api/endpoint/getappealpdfdocuments_api.js` -3. `[x]` Apply file hash-guard flow consistency slice - - `pages/api/file/deleteblob.js` - - `pages/api/file/deleteawaitingsubmissionfromblob.js` - - `pages/api/file/getprogressobjblob.js` - - `pages/api/file/getbloblist.js` -4. `[x]` Apply create/update input-guard + logging hygiene slice - - `pages/api/file/createcase_api.js` - - `pages/api/file/updatecase_api.js` - - `pages/api/file/editRepJson.js` -5. `[x]` Add focused phase-18 behavioural tests - - added `tests/phase18/service-behaviour.test.cjs` - - negative-path coverage for required inputs/hash - - contract-preserving happy-path checks on selected handlers -6. `[x]` Execute validation bundle - - phase6 parity + phase6–phase18 behavioural tests all pass - - lint warnings only (pre-existing `react-hooks/exhaustive-deps` set) - -### Phase 18 rollback notes - -- Revert files in this slice: - - `pages/api/endpoint/deletewatchedcases_api.js` - - `pages/api/endpoint/getaccounts_api.js` - - `pages/api/endpoint/getbasicsearchpaged_api.js` - - `pages/api/endpoint/getappealpdfdocuments_api.js` - - `pages/api/file/deleteblob.js` - - `pages/api/file/deleteawaitingsubmissionfromblob.js` - - `pages/api/file/getprogressobjblob.js` - - `pages/api/file/getbloblist.js` - - `pages/api/file/createcase_api.js` - - `pages/api/file/updatecase_api.js` - - `pages/api/file/editRepJson.js` - - `tests/phase18/service-behaviour.test.cjs` -- Re-run phase6–phase18 baseline tests and lint after rollback to confirm parity. - -### Phase 19 endpoint consistency slice snapshot (2026-03-14) - -Status key: `[x] done`, `[ ] pending` - -1. `[x]` Apply small consistency-only endpoint hardening in selected handlers - - `pages/api/endpoint/createwatchedcases_api.js` - - `pages/api/endpoint/getappealtypes_api.js` - - `pages/api/endpoint/getdnslist_api.js` -2. `[x]` Standardize negative-path required input handling - - early 400 on missing/malformed required `@odata.bind` values in `createwatchedcases_api` -3. `[x]` Remove noisy sensitive-path logging - - removed direct query logging in appeal-types and dns-list handlers -4. `[x]` Add focused tests - - `tests/phase19/service-behaviour.test.cjs` (5/5) -5. `[x]` Execute validation bundle - - phase6 parity + phase6–phase19 behavioural suites pass - - lint warnings only (pre-existing) - -### Phase 19 rollback notes - -- Revert files in this slice: - - `pages/api/endpoint/createwatchedcases_api.js` - - `pages/api/endpoint/getappealtypes_api.js` - - `pages/api/endpoint/getdnslist_api.js` - - `tests/phase19/service-behaviour.test.cjs` -- Re-run phase6–phase19 baseline tests and lint after rollback. - -### Phase 20 endpoint consistency slice snapshot (2026-03-14) - -Status key: `[x] done`, `[ ] pending` - -1. `[x]` Apply small consistency-only endpoint hardening in selected handlers - - `pages/api/endpoint/getbasicdnssearch_api.js` - - `pages/api/endpoint/getbasicdnsurlsearch_api.js` - - `pages/api/endpoint/getbasicsearchdetailspaged_api.js` -2. `[x]` Standardize negative-path required input handling - - early 400 for missing/empty `searchString` in `getbasicdnsurlsearch_api` - - early 400 for missing required params in `getbasicsearchdetailspaged_api` -3. `[x]` Remove noisy sensitive-path logging - - removed direct query logging in `getbasicdnssearch_api` -4. `[x]` Add focused tests - - `tests/phase20/service-behaviour.test.cjs` (5/5) -5. `[x]` Execute validation bundle - - phase6 parity + phase6–phase20 behavioural suites pass - - lint warnings only (pre-existing) - -### Phase 20 rollback notes - -- Revert files in this slice: - - `pages/api/endpoint/getbasicdnssearch_api.js` - - `pages/api/endpoint/getbasicdnsurlsearch_api.js` - - `pages/api/endpoint/getbasicsearchdetailspaged_api.js` - - `tests/phase20/service-behaviour.test.cjs` -- Re-run phase6–phase20 baseline tests and lint after rollback. - -### Phase 21 endpoint contract slice snapshot (2026-03-19) - -Status key: `[x] done`, `[ ] pending` - -1. `[x]` Confirm work item + branch from `origin/SIPS-Development` - - work item: `TASK22168` - - branch: `TASK22168-endpoint-account-contract-consistency` -2. `[x]` Select next coherent low-risk endpoint contract slice after TASK22109 - - selected handlers: - - `getaccounts_api` - - `getemailaccountcheck_api` - - `getpreferredlanguage_api` -3. `[x]` Apply consistency pattern from TASK22109 - - remove dead/noisy code (unused imports/commented debug remnants) - - standardize structured negative-path responses (missing required input + catch path) - - preserve success payload behavior -4. `[x]` Add focused phase21 tests for endpoint slice - - added `tests/phase21/endpoint-handler-contract.test.cjs` - - extended `tests/phase21/api-contract-slice1.test.cjs` runner -5. `[x]` Execute required validation - - `node tests/phase21/api-contract-slice1.test.cjs` -> pass - - `npm run lint` -> warnings only (pre-existing) - -### Phase 21 rollback notes - -- Revert files: - - `pages/api/endpoint/getaccounts_api.js` - - `pages/api/endpoint/getemailaccountcheck_api.js` - - `pages/api/endpoint/getpreferredlanguage_api.js` - - `tests/phase21/endpoint-handler-contract.test.cjs` - - `tests/phase21/api-contract-slice1.test.cjs` -- Re-run: - - `node tests/phase21/api-contract-slice1.test.cjs` - - `npm run lint` - -### Phase 21 Bundle C extension snapshot (2026-03-19) - -Status key: `[x] done`, `[ ] pending` - -1. `[x]` Confirm user preference for larger same-branch bundle - - selected: Bundle C -2. `[x]` Extend endpoint consistency in login/portal/account adjacency handlers - - `getlogin_api` - - `getportallogin_api` - - `getportalloginproxy_api` - - `getpersonalaccount_api` -3. `[x]` Apply consistency pattern - - remove dead/noisy imports/logging remnants - - standardize structured negative-path responses (required input + catch/failure) - - preserve success contracts -4. `[x]` Expand phase21 endpoint tests - - `tests/phase21/endpoint-handler-contract.test.cjs` expanded to 18 tests -5. `[x]` Execute required validation - - `node tests/phase21/api-contract-slice1.test.cjs` -> pass - - `npm run lint` -> warnings only (pre-existing) - -### Phase 21 Bundle C rollback notes - -- Revert files: - - `pages/api/endpoint/getlogin_api.js` - - `pages/api/endpoint/getportallogin_api.js` - - `pages/api/endpoint/getportalloginproxy_api.js` - - `pages/api/endpoint/getpersonalaccount_api.js` - - `tests/phase21/endpoint-handler-contract.test.cjs` -- Re-run: - - `node tests/phase21/api-contract-slice1.test.cjs` - - `npm run lint` - -## Safe execution mode for migration chunks (required) - -To reduce terminal hangs during bulk migration work, run refactor chunks in **safe stepwise mode** instead of long chained commands. - -Required command pattern: - -1. Read/inspect target files. -2. Apply edits only. -3. Verify with targeted grep for remaining broad imports. -4. Check `git status`. -5. Stage files. -6. Commit. -7. Re-run verification and then continue to the next chunk. - -Rules: - -- Do **not** combine edit + verify + add + commit + log in one long chained command. -- Keep each terminal call short and single-purpose. -- If a command is interrupted, re-check `git status` and resume from the next incomplete step. -- Preserve smallest viable diff and behavior parity. - -## Implementation status snapshot (2026-03-12) - -- Phase 1 completed: - - Extracted core helpers into `actions/core/{env,logger,hash,token,headers}.js`. - - Moved wrapper functions into `actions/services/legacyActionsService.js`. - - Reduced `actions/index.js` to compatibility barrel re-exports. - - Added `actions/clients/README.md` scaffold for upcoming client extraction. -- Validation status: - - `npm run lint` currently fails at framework/tooling option level (legacy ESLint options), not due to this refactor logic. - - Manual test matrix is required next (search/case/myportal/auth/notify/file). - -## Implementation status snapshot (Phase 2 update — 2026-03-12) - -- Phase 2 completed: - - Added grouped service modules under `actions/services/`: - - `searchService.js` - - `caseService.js` - - `accountService.js` - - `portalService.js` - - `documentService.js` - - `referenceDataService.js` - - `notifyService.js` - - `adminService.js` - - `integrationService.js` - - Added `actions/services/index.js` barrel. - - Updated `actions/index.js` to export from `./services` and `./core/*`. - - Verified export parity: all `legacyActionsService` exports are represented by grouped service modules. -- Current compatibility model: - - Consumers can continue importing from `../actions` with unchanged function names/signatures. - - `legacyActionsService` remains an internal compatibility implementation module until Phase 3 consumer migration. - -## Implementation status snapshot (Phase 3 update — 2026-03-12) - -- Phase 3 started with targeted consumer migration to focused imports. -- Updated high-churn consumers: - - `components/case/summary.js` - - `createWatchedCases`, `deleteWatchedCases`, `getWatchedCasesProxy`, `setCaseInvolvment` -> `actions/services/portalService` - - `getLinkedCases` -> `actions/services/searchService` - - `getPortalModuleDetailsProxy` -> `actions/services/caseService` - - `pages/api/email/notify.js` - - `consoleLogger` -> `actions/core/logger` - - `getPreferredLanguage` -> `actions/services/accountService` -- Updated selected endpoint handlers to core imports: - - `pages/api/endpoint/getwatchedcases_api.js` - - `pages/api/endpoint/getadvancedsearchpaged_api.js` - - `pages/api/endpoint/getpreferredlanguage_api.js` - - `pages/api/endpoint/createcrmtask_api.js` -- Compatibility remains preserved via `actions/index.js` barrel while migration proceeds incrementally. - -## Implementation status snapshot (Phase 4 update — 2026-03-12) - -- Phase 4 started with targeted hardening helpers and sensitive-path adoption. -- Added `actions/core/guards.js` with: - - `isNonEmptyString` - - `sanitizeString` - - `escapeODataString` -- Expanded `actions/core/logger.js` with redaction support: - - `redactSensitive` - - masking for likely email/token/secret patterns in logged content -- Updated `actions/index.js` compatibility barrel to export `./core/guards`. -- Applied hardening in selected sensitive/high-churn handlers: - - `pages/api/email/notify.js` - - email input sanitization + required-field guard - - redacted logging for outbound payload diagnostics - - `pages/api/endpoint/getpreferredlanguage_api.js` - - sanitized/validated `emailAddress` - - OData string escaping for query construction - - redacted query logging - - `pages/api/endpoint/createcrmtask_api.js` - - sanitized/validated request inputs for subject/email/body - - centralized structured error logging via `consoleLogger` - -## Implementation status snapshot (Priority 1 execution pass — 2026-03-12) - -- Completed another targeted consumer migration pass from broad `actions` barrel imports to focused service/core imports in these files: - - `components/admin/tabs/documents.js` - - `components/admin/tabs/storage.js` - - `components/admin/utils/serverside.js` - - `components/case/documents.js` - - `components/case/representation/representationComplete.js` - - `components/case/representation/representationElements.js` - - `components/elements/index.js` - - `components/myportal/awaitingsubmissionfromblob.js` - - `components/myportal/topthree.js` - - `components/myportal/topthree_reps.js` - - `components/utils/index.js` - - `lib/myportal/loadMyPortalAppealPage.js` - - `lib/newappeal/loadNewAppealPage.js` -- Kept compatibility behavior via existing `actions/index.js` barrel. -- Validation note: `npm run lint` remains blocked by repository ESLint/Next option incompatibility (pre-existing tooling configuration). - -## Goal - -Reduce coupling and regression risk by splitting `actions/index.js` into focused modules while preserving existing behavior and call signatures during migration. - -## Why this is first - -`actions/index.js` is currently a high-risk hotspot: API wrappers, relay/hash helpers, token acquisition, logging, file helpers, and notification helpers are mixed in one module. This increases blast radius for every change. - -## Scope (planned) - -- In scope: - - Module extraction and internal architecture cleanup. - - Backward-compatible export strategy. - - Migration plan for consumers under `components/**`, `pages/**`, and `pages/api/**`. -- Out of scope (for this refactor phase): - - Functional changes to business logic. - - Contract changes to API handlers. - - Dependency swaps. - -## Proposed target structure - -```text -actions/ - index.js # compatibility barrel (temporary) - core/ - env.js # BASE_URL/API_ROOT/relay roots - logger.js # consoleLogger/conLog with redaction helpers - hash.js # hashAPIPath/hashString/dehashString - token.js # getToken + token request config - headers.js # azureHeaders* helpers - clients/ - relayClient.js # signed relay calls + shared axios behavior - endpointClient.js # endpoint route wrappers - fileClient.js # file route wrappers - notifyClient.js # email/notify wrappers - services/ - caseService.js - searchService.js - portalService.js - accountService.js - documentService.js -``` - -Notes: - -- Keep `actions/index.js` as a façade initially to avoid breaking imports. -- Move internals first, then update call sites incrementally. - -## Migration strategy (phased) - -### Phase 1 — Safe extraction with no consumer changes - -1. Create new modules under `actions/core/**` and `actions/clients/**`. -2. Move utility functions (`hash`, `headers`, `token`, `logger`, env helpers). -3. Re-export all existing functions from `actions/index.js` unchanged. -4. Verify parity with lint + smoke checks. - -### Phase 2 — Service grouping - -1. Group route wrapper functions into service modules by domain (case/search/portal/account/document). -2. Keep identical function names/signatures. -3. Add thin unit tests for pure helpers first (`hash`, `env`, route builder helpers). - -### Phase 3 — Consumer migration - -1. Replace broad imports from `actions/index.js` with targeted imports from new modules. -2. Migrate high-churn areas first: - - `components/breadcrumbs.js` - - `components/case/summary.js` - - `pages/api/email/notify.js` - - selected `pages/api/endpoint/**` handlers -3. Keep index barrel until migration completion. - -### Phase 4 — Harden + slim - -1. Introduce typed/validated request helper boundaries (JS doc + runtime guard checks). -2. Remove dead exports and duplicate wrappers. -3. Finalize redacted logging policy in sensitive flows. - -## Backward compatibility rules - -- Do not change public function names/signatures during Phases 1–2. -- Keep return shapes identical unless explicitly planned and validated. -- Preserve existing hash and relay behavior contract. -- Preserve EN/CY behavior where helper functions influence locale-sensitive flows. - -## Validation plan - -- `npm run lint` -- Manual smoke paths: - - search -> results -> case summary -> back nav - - myportal viewall -> case summary -> breadcrumb return path - - auth email sign-in flow - - notify new case reference language selection path - - file/document fetch paths touched by moved wrappers -- Negative-path checks: - - invalid hash or malformed query for sensitive handlers - - token acquisition failures and relay timeout handling - -## Regression tests and coverage plan (to add during implementation) - -### Test tooling recommendation - -Current repo has no active automated test runner configured in `package.json`. For this refactor, introduce a minimal unit test setup (recommended: Jest) focused on pure logic first. - -Suggested scripts: - -- `test`: run all unit tests -- `test:watch`: local watch mode -- `test:coverage`: coverage output for CI and PR evidence - -### Minimum tests for Priority 1 - -1. `actions/core/hash.js` - - deterministic hash for known input - - query string handling (`?hash=` vs `&hash=`) - - malformed/edge inputs -2. `actions/core/headers.js` - - expected OData/auth headers produced for each helper -3. `actions/core/token.js` - - token request config generation - - success and error mapping behavior (mock axios) -4. `actions/core/env.js` - - server vs browser base URL resolution -5. compatibility barrel (`actions/index.js`) - - exports parity test to ensure existing function names remain available during migration - -### Integration-style safeguards (mocked external calls) - -- Relay client request assembly test: - - signed URL includes hash - - token is attached - - timeout/error behavior is consistent -- Notify client wrapper test: - - language/template routing remains unchanged for PEDW-NEW-CASEREF path - -### Coverage targets for this refactor - -- `actions/core/**`: >= 90% lines/functions -- `actions/clients/**`: >= 80% lines/functions -- Global coverage gate for this phase: >= 70% (new tests only; avoid blocking unrelated legacy code) - -### Regression gate in PR - -Required evidence for each phase: - -1. `npm run lint` -2. `npm run test` -3. `npm run test:coverage` (attach summary) -4. Manual smoke matrix from this plan (search/case/myportal/auth/notify/file) - -## Risks and mitigations - -- Risk: import breakage due to broad existing usage. - - Mitigation: keep compatibility barrel and migrate in small batches. -- Risk: hidden behavior differences from refactor-only moves. - - Mitigation: freeze signatures + add helper tests + run route smoke matrix each phase. -- Risk: sensitive logging leakage while touching shared helpers. - - Mitigation: centralize logger early and enforce redaction helper. - -## Definition of done (for this priority) - -1. `actions/index.js` reduced to compatibility exports only (minimal logic). -2. Core helper modules and service modules exist and are used by migrated consumers. -3. Lint and manual validation matrix pass. -4. Memory docs updated (`activeContext`, `progress`, `change-log`). diff --git a/pages/api/endpoint/createaccount_api.js b/pages/api/endpoint/createaccount_api.js index 8c8468c8..67a5f1ea 100644 --- a/pages/api/endpoint/createaccount_api.js +++ b/pages/api/endpoint/createaccount_api.js @@ -11,40 +11,51 @@ */ import axios from "axios"; -import CryptoJS from "crypto-js"; import { consoleLogger } from "../../../actions/core/logger"; import { getToken } from "../../../actions/core/token"; import { hashAPIPath } from "../../../actions/core/hash"; +import { respondError, respondSuccess } from "../middleware/apiResponse"; const WEBAPI_URL = process.env.RELAY_ROOT || "https://dev-pedw-ns.servicebus.windows.net/dev-pedw-hc/"; export default async function ApiProxy(req, res) { - var token = await getToken(); - var queryUrl = "contacts"; - var data = JSON.stringify(req.body); - - var config = { - method: "post", - url: WEBAPI_URL + queryUrl + hashAPIPath(queryUrl), - headers: { - "OData-MaxVersion": "4.0", - "OData-Version": "4.0", - "Accept": "application/json", - "Prefer": 'odata.include-annotations="*",return=representation', - "Authorization": "Bearer " + token.access_token, - "Content-Type": "application/json" - }, - data: data - }; - - return axios(config) - .then(({ data }) => { - res.status(200).json(data); - }) - .catch((error) => { - consoleLogger(error); - res.status(400).json(error); + if (!req.body || Object.keys(req.body).length === 0) { + return respondError(res, { + status: 400, + code: "ACCOUNT_PAYLOAD_REQUIRED", + message: "Account payload is required" }); + } + + try { + const token = await getToken(); + const queryUrl = "contacts"; + const data = JSON.stringify(req.body); + + const config = { + method: "post", + url: WEBAPI_URL + queryUrl + hashAPIPath(queryUrl), + headers: { + "OData-MaxVersion": "4.0", + "OData-Version": "4.0", + Accept: "application/json", + Prefer: 'odata.include-annotations="*",return=representation', + Authorization: "Bearer " + token.access_token, + "Content-Type": "application/json" + }, + data + }; + + const response = await axios(config); + return respondSuccess(res, response.data); + } catch (error) { + consoleLogger(error); + return respondError(res, { + status: 400, + code: "ACCOUNT_CREATE_FAILED", + message: "Failed to create account" + }); + } } diff --git a/pages/api/endpoint/getadvancedsearch_api.js b/pages/api/endpoint/getadvancedsearch_api.js index 77b09fe7..2f504689 100644 --- a/pages/api/endpoint/getadvancedsearch_api.js +++ b/pages/api/endpoint/getadvancedsearch_api.js @@ -22,149 +22,149 @@ */ import axios from "axios"; -import CryptoJS from "crypto-js"; -import _ from "lodash"; import { azureHeadersPaged } from "../../../actions/core/headers"; import { consoleLogger } from "../../../actions/core/logger"; import { getToken } from "../../../actions/core/token"; import { hashAPIPath } from "../../../actions/core/hash"; +import { respondError, respondSuccess } from "../middleware/apiResponse"; const WEBAPI_URL = process.env.RELAY_ROOT || "https://dev-pedw-ns.servicebus.windows.net/dev-pedw-hc/"; export default async function ApiProxy(req, res) { - var searchString = req.query.searchstring; - var token = await getToken(); + const encodedSearchString = req.query.searchstring; - searchString = _.isEmpty(searchString) - ? searchString - : JSON.parse(decodeURI(searchString)); + if ( + typeof encodedSearchString !== "string" || + encodedSearchString.trim().length === 0 + ) { + return respondError(res, { + status: 400, + code: "SEARCH_STRING_REQUIRED", + message: "searchstring is required" + }); + } - var queryString = ""; + let searchString; + try { + searchString = JSON.parse(decodeURI(encodedSearchString)); + } catch (error) { + return respondError(res, { + status: 400, + code: "INVALID_SEARCH_STRING", + message: "searchstring must be valid JSON" + }); + } + + if ( + !searchString || + typeof searchString !== "object" || + Object.keys(searchString).length === 0 + ) { + return respondError(res, { + status: 400, + code: "SEARCH_STRING_REQUIRED", + message: "searchstring is required" + }); + } + + const toEscapedString = (value) => String(value).replace(/\'/g, "''"); + let queryString = ""; queryString += - _.has(searchString, "q") && searchString.q != null + searchString.q != null ? "(contains(title, '" + - searchString.q.replace(/\'/g, "''") + + toEscapedString(searchString.q) + "') or contains(ticketnumber,'" + - searchString.q.replace(/\'/g, "''") + + toEscapedString(searchString.q) + "')) and" : ""; queryString += - _.has(searchString, "lpaRef") && searchString.lpaRef != null + searchString.lpaRef != null ? "(contains(pinswg_lpareference, '" + - searchString.lpaRef.replace(/\'/g, "''") + + toEscapedString(searchString.lpaRef) + "')) and" : ""; queryString += - (_.has(searchString, "lpa") || _.has(searchString, "LPA")) && + (searchString.lpa != null || searchString.LPA != null) && searchString.lpa != null ? " _pinswg_associatedlpa_value eq " + searchString.lpa + " and" : ""; queryString += - _.has(searchString, "apt") && searchString.apt != null + searchString.apt != null ? " pinswg_appealcasetype eq " + searchString.apt + " and" : ""; queryString += - _.has(searchString, "statuscode") && searchString.statuscode != null + searchString.statuscode != null ? " statuscode eq " + searchString.statuscode + " and" : ""; - //console.log(queryString); - - var queryUrl = + const queryUrl = "incidents?$select=pinswg_environmentalstatementlocation,pinswg_caseaddress,modifiedon,description,numberofchildincidents,_accountid_value,_customerid_value,_pinswg_associatedlpa_value,_ownerid_value,pinswg_appealcasetype,statuscode,ticketnumber,title,_primarycontactid_value,pinswg_lpareference,pinswg_appellantagent,pinswg_appellantfirstname,pinswg_appellantlastname&$expand=primarycontactid($select=fullname)&$filter=" + queryString + " pinswg_appealcasetype ne null and pinswg_publishtoweb eq true&$orderby=createdon desc&$count=true"; - //console.log(queryString, "\n", queryUrl); + try { + const token = await getToken(); + const { data } = await axios.get( + WEBAPI_URL + queryUrl + hashAPIPath(queryUrl), + azureHeadersPaged(token.access_token) + ); - var apiResponse = _.isEmpty(searchString) - ? res.status(400).json() - : axios - .get( - WEBAPI_URL + queryUrl + hashAPIPath(queryUrl), - azureHeadersPaged(token.access_token) - ) - .then(async ({ data }) => { - var dataStr; - _.has(data, "@odata.nextLink") == true && - ((dataStr = JSON.stringify(data["@odata.nextLink"])), - (data["@odata.nextLink"] = dataStr.split("/v8.2/")[1])); + if (Object.prototype.hasOwnProperty.call(data, "@odata.nextLink")) { + const dataStr = JSON.stringify(data["@odata.nextLink"]); + data["@odata.nextLink"] = dataStr.split("/v8.2/")[1]; + } - if (_.has(searchString, "projecttype")) { - await updateValueArray(data, token); + if (searchString.projecttype != null) { + for (let i = 0; i < data.value.length; i++) { + const item = data.value[i]; - async function updateValueArray(data, token) { - for (let i = 0; i < data.value.length; i++) { - const item = data.value[i]; + try { + const projectTypeQuery = + "pinswg_sipses?$filter=_pinswg_sipscase_value eq " + + item.incidentid + + " and _pinswg_projecttype_value eq " + + searchString.projecttype + + "&$select=_pinswg_projecttype_value"; - try { - // Axios call using the `incidentid` to fetch additional data - const response = await axios.get( - WEBAPI_URL + - "pinswg_sipses?$filter=_pinswg_sipscase_value eq " + - item.incidentid + - " and _pinswg_projecttype_value eq " + - searchString.projecttype + - "&$select=_pinswg_projecttype_value" + - hashAPIPath( - "pinswg_sipses?$filter=_pinswg_sipscase_value eq " + - item.incidentid + - " and _pinswg_projecttype_value eq " + - searchString.projecttype + - "&$select=_pinswg_projecttype_value" - ), - azureHeadersPaged(token.access_token) - ); + const response = await axios.get( + WEBAPI_URL + + projectTypeQuery + + hashAPIPath(projectTypeQuery), + azureHeadersPaged(token.access_token) + ); - // Assuming the response contains the additional data you want to add - // console.log(response.data.value[0]); - console.log(response.data.value); + if ( + response.data.value.length > 0 && + response.data.value[0]._pinswg_projecttype_value != null + ) { + Object.assign(item, response.data.value[0]); + } + } catch (error) { + consoleLogger(error); + } + } - if ( - response.data.value.length > 0 && - response.data.value[0] - ._pinswg_projecttype_value != null - ) { - Object.assign( - item, - response.data.value[0] - ); // Update item with new data - } else { - console.log( - `No project type found for incident ID ${item.incidentid}` - ); - } - } catch (error) { - console.error( - `Error fetching data for incident ID ${item.incidentid}:`, - error - ); - } - } - } + data.value = data.value.filter( + (item) => item._pinswg_projecttype_value != null + ); - data.value = data.value.filter( - (item) => item._pinswg_projecttype_value != null - ); + data["@odata.count"] = data.value.length; + } - data["@odata.count"] = data.value.length; - - // console.log(newDataObj); - } - - res.status(200).json(data); - }) - .catch((error) => { - consoleLogger(error); - res.status(400).json(error); - }); - - return apiResponse; + return respondSuccess(res, data); + } catch (error) { + consoleLogger(error); + return respondError(res, { + status: 400, + code: "ADVANCED_SEARCH_FETCH_FAILED", + message: "Failed to fetch advanced search results" + }); + } } diff --git a/pages/api/endpoint/getawaitingsubmissionproxy_api.js b/pages/api/endpoint/getawaitingsubmissionproxy_api.js index 206680bf..3654ba02 100644 --- a/pages/api/endpoint/getawaitingsubmissionproxy_api.js +++ b/pages/api/endpoint/getawaitingsubmissionproxy_api.js @@ -11,39 +11,53 @@ */ import axios from "axios"; -import CryptoJS from "crypto-js"; import { azureHeaders } from "../../../actions/core/headers"; import { consoleLogger } from "../../../actions/core/logger"; import { getToken } from "../../../actions/core/token"; import { hashAPIPath } from "../../../actions/core/hash"; +import { respondError, respondSuccess } from "../middleware/apiResponse"; const WEBAPI_URL = process.env.RELAY_ROOT || "https://dev-pedw-ns.servicebus.windows.net/dev-pedw-hc/"; export default async function ApiProxy(req, res) { - var loggedInUserId = req.query.loggedInUserId; - var token = await getToken(); + const loggedInUserId = req.query.loggedInUserId; - var queryUrl = - "incidents?$select=pinswg_environmentalstatementlocation,modifiedon,description,numberofchildincidents,_accountid_value,_customerid_value,_pinswg_associatedlpa_value,_ownerid_value,pinswg_appealcasetype,statuscode,ticketnumber,title, _primarycontactid_value,pinswg_lpareference,pinswg_appellantlastname,pinswg_appellantfirstname,pinswg_appellantagent,pinswg_agentfirstname,pinswg_agentlastname,pinswg_agentcompanyname&$expand=primarycontactid($select=fullname)&$filter=_customerid_value eq " + - loggedInUserId + - " and pinswg_appealcasetype ne null&$orderby=createdon desc&$count=true"; + if ( + typeof loggedInUserId !== "string" || + loggedInUserId.trim().length === 0 + ) { + return respondError(res, { + status: 400, + code: "LOGGED_IN_USER_ID_REQUIRED", + message: "loggedInUserId is required" + }); + } - //console.log(WEBAPI_URL + queryUrl + hashAPIPath(queryUrl)); - return axios - .get( + try { + const token = await getToken(); + const queryUrl = + "incidents?$select=pinswg_environmentalstatementlocation,modifiedon,description,numberofchildincidents,_accountid_value,_customerid_value,_pinswg_associatedlpa_value,_ownerid_value,pinswg_appealcasetype,statuscode,ticketnumber,title, _primarycontactid_value,pinswg_lpareference,pinswg_appellantlastname,pinswg_appellantfirstname,pinswg_appellantagent,pinswg_agentfirstname,pinswg_agentlastname,pinswg_agentcompanyname&$expand=primarycontactid($select=fullname)&$filter=_customerid_value eq " + + loggedInUserId + + " and pinswg_appealcasetype ne null&$orderby=createdon desc&$count=true"; + + const { data } = await axios.get( WEBAPI_URL + queryUrl + hashAPIPath(queryUrl), azureHeaders(token.access_token) - ) - .then(({ data }) => { - data.value.forEach(function (element) { - element.pinswg_title = element.title; - }); - res.status(200).json(data); - }) - .catch((error) => { - consoleLogger(error); - res.status(400).json(error); + ); + + data.value.forEach(function (element) { + element.pinswg_title = element.title; }); + + return respondSuccess(res, data); + } catch (error) { + consoleLogger(error); + return respondError(res, { + status: 400, + code: "AWAITING_SUBMISSION_PROXY_FETCH_FAILED", + message: "Failed to fetch awaiting submission proxy details" + }); + } } diff --git a/pages/api/endpoint/getbasicsearch_api.js b/pages/api/endpoint/getbasicsearch_api.js index d0b2cb73..c7d5d604 100644 --- a/pages/api/endpoint/getbasicsearch_api.js +++ b/pages/api/endpoint/getbasicsearch_api.js @@ -16,65 +16,61 @@ */ import axios from "axios"; -import CryptoJS from "crypto-js"; -import _ from "lodash"; import { azureHeadersPaged } from "../../../actions/core/headers"; import { consoleLogger } from "../../../actions/core/logger"; import { getToken } from "../../../actions/core/token"; import { hashAPIPath } from "../../../actions/core/hash"; +import { respondError, respondSuccess } from "../middleware/apiResponse"; const WEBAPI_URL = process.env.RELAY_ROOT || "https://dev-pedw-ns.servicebus.windows.net/dev-pedw-hc/"; export default async function ApiProxy(req, res) { - var searchString = req.query.searchString; - var token = await getToken(); + const searchString = req.query.searchString; - searchString = searchString.replace(/\'/g, "''"); + if (typeof searchString !== "string" || searchString.trim().length === 0) { + return respondError(res, { + status: 400, + code: "SEARCH_STRING_REQUIRED", + message: "searchString is required" + }); + } - var queryUrl = - "incidents?$select=pinswg_environmentalstatementlocation,pinswg_caseaddress,modifiedon,description,numberofchildincidents,_accountid_value,_customerid_value,_pinswg_associatedlpa_value,_ownerid_value,pinswg_appealcasetype,statuscode,ticketnumber,title, _primarycontactid_value,pinswg_lpareference,pinswg_appellantagent,pinswg_appellantfirstname,pinswg_appellantlastname&$expand=primarycontactid($select=fullname)&$filter=(contains(title, '" + - searchString + - "') or contains(ticketnumber, '" + - searchString + - "') or contains(pinswg_lpareference, '" + - searchString + - "')) and pinswg_appealcasetype ne null " + - (process.env.SHOWSIPS !== "true" - ? "and pinswg_appealcasetype ne 846040002 " - : "") + - "and pinswg_publishtoweb eq true&$orderby=createdon desc&$count=true"; + try { + const token = await getToken(); + const escapedSearchString = searchString.replace(/\'/g, "''"); - console.log( - "\n==========================================\n", - "\nBasic search ", - "\nSearch String: " + searchString, - "\n\nQuery url: " + queryUrl, - "\n\nRelay link: " + WEBAPI_URL + queryUrl + hashAPIPath(queryUrl), - "\n==========================================\n" - ); + const queryUrl = + "incidents?$select=pinswg_environmentalstatementlocation,pinswg_caseaddress,modifiedon,description,numberofchildincidents,_accountid_value,_customerid_value,_pinswg_associatedlpa_value,_ownerid_value,pinswg_appealcasetype,statuscode,ticketnumber,title, _primarycontactid_value,pinswg_lpareference,pinswg_appellantagent,pinswg_appellantfirstname,pinswg_appellantlastname&$expand=primarycontactid($select=fullname)&$filter=(contains(title, '" + + escapedSearchString + + "') or contains(ticketnumber, '" + + escapedSearchString + + "') or contains(pinswg_lpareference, '" + + escapedSearchString + + "')) and pinswg_appealcasetype ne null " + + (process.env.SHOWSIPS !== "true" + ? "and pinswg_appealcasetype ne 846040002 " + : "") + + "and pinswg_publishtoweb eq true&$orderby=createdon desc&$count=true"; - var apiResponse = _.isEmpty(req.query) - ? res.status(400).json() - : searchString.length > 0 - ? axios - .get( - WEBAPI_URL + queryUrl + hashAPIPath(queryUrl), - azureHeadersPaged(token.access_token) - ) - .then(({ data }) => { - var dataStr; - _.has(data, "@odata.nextLink") == true && - ((dataStr = JSON.stringify(data["@odata.nextLink"])), - (data["@odata.nextLink"] = dataStr.split("/v8.2/")[1])); - res.status(200).json(data); - }) - .catch((error) => { - consoleLogger(error); - res.status(400).json(error); - }) - : res.status(400).json(); + const { data } = await axios.get( + WEBAPI_URL + queryUrl + hashAPIPath(queryUrl), + azureHeadersPaged(token.access_token) + ); - return apiResponse; + if (Object.prototype.hasOwnProperty.call(data, "@odata.nextLink")) { + const dataStr = JSON.stringify(data["@odata.nextLink"]); + data["@odata.nextLink"] = dataStr.split("/v8.2/")[1]; + } + + return respondSuccess(res, data); + } catch (error) { + consoleLogger(error); + return respondError(res, { + status: 400, + code: "BASIC_SEARCH_FETCH_FAILED", + message: "Failed to fetch basic search results" + }); + } } diff --git a/pages/api/endpoint/getcasemessage_api.js b/pages/api/endpoint/getcasemessage_api.js index 0bf2f3db..8adaf604 100644 --- a/pages/api/endpoint/getcasemessage_api.js +++ b/pages/api/endpoint/getcasemessage_api.js @@ -16,48 +16,47 @@ */ import axios from "axios"; -import CryptoJS from "crypto-js"; -import _ from "lodash"; import { azureHeadersPaged } from "../../../actions/core/headers"; import { consoleLogger } from "../../../actions/core/logger"; import { getToken } from "../../../actions/core/token"; import { hashAPIPath } from "../../../actions/core/hash"; +import { respondError, respondSuccess } from "../middleware/apiResponse"; const WEBAPI_URL = process.env.RELAY_ROOT || "https://dev-pedw-ns.servicebus.windows.net/dev-pedw-hc/"; export default async function ApiProxy(req, res) { - var searchString = req.query.id; - var token = await getToken(); + const caseId = req.query.id; - var queryUrl = `tasks?$select=_regardingobjectid_value,subject,description,createdon,statuscode,scheduledend,scheduledstart&$count=true&$filter=_regardingobjectid_value eq ${searchString} and contains(subject, 'Banner') and statuscode ne 5&$orderby=createdon desc`; + if (typeof caseId !== "string" || caseId.trim().length === 0) { + return respondError(res, { + status: 400, + code: "CASE_ID_REQUIRED", + message: "id is required" + }); + } - console.log( - "\n==========================================\n", - "\nCase messages ", - "\nSearch String: " + searchString, - "\n\nQuery url: " + queryUrl, - "\n\nRelay link: " + WEBAPI_URL + queryUrl + hashAPIPath(queryUrl), - "\n==========================================\n" - ); + try { + const token = await getToken(); - var apiResponse = _.isEmpty(req.query) - ? res.status(400).json() - : searchString.length > 0 - ? axios - .get( - WEBAPI_URL + queryUrl + hashAPIPath(queryUrl), - azureHeadersPaged(token.access_token) - ) - .then(({ data }) => { - res.status(200).json(data); - }) - .catch((error) => { - consoleLogger(error); - res.status(400).json(error); - }) - : res.status(400).json(); + const queryUrl = + "tasks?$select=_regardingobjectid_value,subject,description,createdon,statuscode,scheduledend,scheduledstart&$count=true&$filter=_regardingobjectid_value eq " + + caseId + + " and contains(subject, 'Banner') and statuscode ne 5&$orderby=createdon desc"; - return apiResponse; + const { data } = await axios.get( + WEBAPI_URL + queryUrl + hashAPIPath(queryUrl), + azureHeadersPaged(token.access_token) + ); + + return respondSuccess(res, data); + } catch (error) { + consoleLogger(error); + return respondError(res, { + status: 400, + code: "CASE_MESSAGE_FETCH_FAILED", + message: "Failed to fetch case messages" + }); + } } diff --git a/pages/api/endpoint/getmyrepresentationsproxy_api.js b/pages/api/endpoint/getmyrepresentationsproxy_api.js index 8fa44901..df6da9e3 100644 --- a/pages/api/endpoint/getmyrepresentationsproxy_api.js +++ b/pages/api/endpoint/getmyrepresentationsproxy_api.js @@ -18,35 +18,50 @@ */ import axios from "axios"; -import CryptoJS from "crypto-js"; import { azureHeaders } from "../../../actions/core/headers"; import { consoleLogger } from "../../../actions/core/logger"; import { getToken } from "../../../actions/core/token"; import { hashAPIPath } from "../../../actions/core/hash"; +import { respondError, respondSuccess } from "../middleware/apiResponse"; const WEBAPI_URL = process.env.RELAY_ROOT || "https://dev-pedw-ns.servicebus.windows.net/dev-pedw-hc/"; export default async function ApiProxy(req, res) { - var loggedInUserId = req.query.loggedInUserId; - var token = await getToken(); + const loggedInUserId = req.query.loggedInUserId; - var queryUrl = - "pinswg_representationses?$filter= _pinswg_contact_value eq " + - loggedInUserId + - "&$count=true&$orderby=createdon desc"; + if ( + typeof loggedInUserId !== "string" || + loggedInUserId.trim().length === 0 + ) { + return respondError(res, { + status: 400, + code: "LOGGED_IN_USER_ID_REQUIRED", + message: "loggedInUserId is required" + }); + } - return axios - .get( + try { + const token = await getToken(); + + const queryUrl = + "pinswg_representationses?$filter= _pinswg_contact_value eq " + + loggedInUserId + + "&$count=true&$orderby=createdon desc"; + + const { data } = await axios.get( WEBAPI_URL + queryUrl + hashAPIPath(queryUrl), azureHeaders(token.access_token) - ) - .then(({ data }) => { - res.status(200).json(data); - }) - .catch((error) => { - consoleLogger(error); - res.status(400).json(error); + ); + + return respondSuccess(res, data); + } catch (error) { + consoleLogger(error); + return respondError(res, { + status: 400, + code: "MY_REPRESENTATIONS_PROXY_FETCH_FAILED", + message: "Failed to fetch my representations proxy details" }); + } } diff --git a/pages/api/endpoint/getrepresentationsproxy_api.js b/pages/api/endpoint/getrepresentationsproxy_api.js index 6d7169ab..88bf23c8 100644 --- a/pages/api/endpoint/getrepresentationsproxy_api.js +++ b/pages/api/endpoint/getrepresentationsproxy_api.js @@ -18,35 +18,47 @@ */ import axios from "axios"; -import CryptoJS from "crypto-js"; import { azureHeaders } from "../../../actions/core/headers"; import { consoleLogger } from "../../../actions/core/logger"; import { getToken } from "../../../actions/core/token"; import { hashAPIPath } from "../../../actions/core/hash"; +import { respondError, respondSuccess } from "../middleware/apiResponse"; const WEBAPI_URL = process.env.RELAY_ROOT || "https://dev-pedw-ns.servicebus.windows.net/dev-pedw-hc/"; export default async function ApiProxy(req, res) { - var incidentID = req.query.incidentID; - var token = await getToken(); + const incidentID = req.query.incidentID; - var queryUrl = - "pinswg_representationses?$filter= _pinswg_case_value eq " + - incidentID + - "&$count=true&$orderby=createdon desc"; + if (typeof incidentID !== "string" || incidentID.trim().length === 0) { + return respondError(res, { + status: 400, + code: "INCIDENT_ID_REQUIRED", + message: "incidentID is required" + }); + } - return axios - .get( + try { + const token = await getToken(); + + const queryUrl = + "pinswg_representationses?$filter= _pinswg_case_value eq " + + incidentID + + "&$count=true&$orderby=createdon desc"; + + const { data } = await axios.get( WEBAPI_URL + queryUrl + hashAPIPath(queryUrl), azureHeaders(token.access_token) - ) - .then(({ data }) => { - res.status(200).json(data); - }) - .catch((error) => { - consoleLogger(error); - res.status(400).json(error); + ); + + return respondSuccess(res, data); + } catch (error) { + consoleLogger(error); + return respondError(res, { + status: 400, + code: "REPRESENTATIONS_PROXY_FETCH_FAILED", + message: "Failed to fetch representations proxy details" }); + } } diff --git a/pages/api/endpoint/getwatchedcasesproxy_api.js b/pages/api/endpoint/getwatchedcasesproxy_api.js index 6101b412..3eb2f147 100644 --- a/pages/api/endpoint/getwatchedcasesproxy_api.js +++ b/pages/api/endpoint/getwatchedcasesproxy_api.js @@ -18,69 +18,75 @@ */ import axios from "axios"; -import CryptoJS from "crypto-js"; import { azureHeaders } from "../../../actions/core/headers"; import { consoleLogger } from "../../../actions/core/logger"; import { getToken } from "../../../actions/core/token"; import { hashAPIPath } from "../../../actions/core/hash"; +import { respondError, respondSuccess } from "../middleware/apiResponse"; const WEBAPI_URL = process.env.RELAY_ROOT || "https://dev-pedw-ns.servicebus.windows.net/dev-pedw-hc/"; -const BASE_URL = process.env.API_ROOT || `http://localhost:${port}`; - export default async function ApiProxy(req, res) { - var loggedInUserId = req.query.loggedInUserId; - var token = await getToken(); + const loggedInUserId = req.query.loggedInUserId; - // var queryUrl = - // "pinswg_watchlists?$filter= _pinswg_contact_value eq " + - // loggedInUserId + - // "&$select=pinswg_emailnotifications,modifiedon,pinswg_appealcasetype,pinswg_watchlistid,_pinswg_watchedcase_value,statuscode,pinswg_representationsubmitted,pinswg_representationtype&$count=true&$orderby=createdon desc&$expand=pinswg_WatchedCase($select=pinswg_AssociatedLPA)"; + if ( + typeof loggedInUserId !== "string" || + loggedInUserId.trim().length === 0 + ) { + return respondError(res, { + status: 400, + code: "LOGGED_IN_USER_ID_REQUIRED", + message: "loggedInUserId is required" + }); + } - var queryUrl = - "pinswg_watchlists?$filter= _pinswg_contact_value eq " + - loggedInUserId + - "&$select=modifiedon,pinswg_appealcasetype,pinswg_watchlistid,_pinswg_watchedcase_value,statuscode,pinswg_representationsubmitted,pinswg_representationtype&$count=true&$orderby=createdon desc&$expand=pinswg_WatchedCase($select=pinswg_AssociatedLPA)"; + try { + const token = await getToken(); + const queryUrl = + "pinswg_watchlists?$filter= _pinswg_contact_value eq " + + loggedInUserId + + "&$select=modifiedon,pinswg_appealcasetype,pinswg_watchlistid,_pinswg_watchedcase_value,statuscode,pinswg_representationsubmitted,pinswg_representationtype&$count=true&$orderby=createdon desc&$expand=pinswg_WatchedCase($select=pinswg_AssociatedLPA)"; - return axios - .get( + const { data } = await axios.get( WEBAPI_URL + queryUrl + hashAPIPath(queryUrl), azureHeaders(token.access_token) - ) - .then(({ data }) => { - data.value.forEach(function (element) { - element.ticketnumber = element.pinswg_WatchedCase.ticketnumber; - element.pinswg_title = - element[ - "_pinswg_watchedcase_value@OData.Community.Display.V1.FormattedValue" - ]; + ); + data.value.forEach(function (element) { + element.ticketnumber = element.pinswg_WatchedCase.ticketnumber; + element.pinswg_title = element[ + "_pinswg_watchedcase_value@OData.Community.Display.V1.FormattedValue" + ]; + + element[ + "_pinswg_associatedlpa_value@OData.Community.Display.V1.FormattedValue" + ] = + element.pinswg_WatchedCase[ "_pinswg_associatedlpa_value@OData.Community.Display.V1.FormattedValue" - ] = - element.pinswg_WatchedCase[ - "_pinswg_associatedlpa_value@OData.Community.Display.V1.FormattedValue" - ]; - element._pinswg_associatedlpa_value = - element.pinswg_WatchedCase._pinswg_associatedlpa_value; - element[ + ]; + element._pinswg_associatedlpa_value = + element.pinswg_WatchedCase._pinswg_associatedlpa_value; + element[ + "_ownerid_value@OData.Community.Display.V1.FormattedValue" + ] = + element.pinswg_WatchedCase[ "_ownerid_value@OData.Community.Display.V1.FormattedValue" - ] = - element.pinswg_WatchedCase[ - "_ownerid_value@OData.Community.Display.V1.FormattedValue" - ]; - element._ownerid_value = - element.pinswg_WatchedCase._ownerid_value; + ]; + element._ownerid_value = element.pinswg_WatchedCase._ownerid_value; - delete element.pinswg_WatchedCase; - }); - - res.status(200).json(data); - }) - .catch((error) => { - consoleLogger(error); - res.status(400).json(error); + delete element.pinswg_WatchedCase; }); + + return respondSuccess(res, data); + } catch (error) { + consoleLogger(error); + return respondError(res, { + status: 400, + code: "WATCHED_CASES_PROXY_FETCH_FAILED", + message: "Failed to fetch watched cases proxy details" + }); + } } diff --git a/pages/api/endpoint/updateaccount_api.js b/pages/api/endpoint/updateaccount_api.js index 72665641..7f7c1f34 100644 --- a/pages/api/endpoint/updateaccount_api.js +++ b/pages/api/endpoint/updateaccount_api.js @@ -11,43 +11,61 @@ */ import axios from "axios"; -import CryptoJS from "crypto-js"; import { consoleLogger } from "../../../actions/core/logger"; import { getToken } from "../../../actions/core/token"; import { hashAPIPath } from "../../../actions/core/hash"; +import { respondError, respondSuccess } from "../middleware/apiResponse"; const WEBAPI_URL = process.env.RELAY_ROOT || "https://dev-pedw-ns.servicebus.windows.net/dev-pedw-hc/"; export default async function ApiProxy(req, res) { - var contactId = req.query.contactId; - var token = await getToken(); - var data = JSON.stringify(req.body); - var queryUrl = "contacts(" + contactId + ")"; + const contactId = req.query.contactId; - var config = { - method: "patch", - url: WEBAPI_URL + queryUrl + hashAPIPath(queryUrl), - headers: { - "OData-MaxVersion": "4.0", - "OData-Version": "4.0", - "Accept": "application/json", - "Prefer": 'odata.include-annotations="*",return=representation', - "Authorization": "Bearer " + token.access_token, - "Content-Type": "application/json" - }, - data: data - }; - - console.log(config); - - return axios(config) - .then(({ data }) => { - res.status(200).json(data); - }) - .catch((error) => { - consoleLogger(error); - res.status(400).json(error); + if (typeof contactId !== "string" || contactId.trim().length === 0) { + return respondError(res, { + status: 400, + code: "CONTACT_ID_REQUIRED", + message: "contactId is required" }); + } + + if (!req.body || Object.keys(req.body).length === 0) { + return respondError(res, { + status: 400, + code: "ACCOUNT_UPDATE_PAYLOAD_REQUIRED", + message: "Account update payload is required" + }); + } + + try { + const token = await getToken(); + const data = JSON.stringify(req.body); + const queryUrl = "contacts(" + contactId + ")"; + + const config = { + method: "patch", + url: WEBAPI_URL + queryUrl + hashAPIPath(queryUrl), + headers: { + "OData-MaxVersion": "4.0", + "OData-Version": "4.0", + Accept: "application/json", + Prefer: 'odata.include-annotations="*",return=representation', + Authorization: "Bearer " + token.access_token, + "Content-Type": "application/json" + }, + data + }; + + const response = await axios(config); + return respondSuccess(res, response.data); + } catch (error) { + consoleLogger(error); + return respondError(res, { + status: 400, + code: "ACCOUNT_UPDATE_FAILED", + message: "Failed to update account" + }); + } } diff --git a/pages/api/endpoint/updatepassword_api.js b/pages/api/endpoint/updatepassword_api.js index c98e6c34..dc8a64cb 100644 --- a/pages/api/endpoint/updatepassword_api.js +++ b/pages/api/endpoint/updatepassword_api.js @@ -11,41 +11,61 @@ */ import axios from "axios"; -import CryptoJS from "crypto-js"; import { consoleLogger } from "../../../actions/core/logger"; import { getToken } from "../../../actions/core/token"; import { hashAPIPath } from "../../../actions/core/hash"; +import { respondError, respondSuccess } from "../middleware/apiResponse"; const WEBAPI_URL = process.env.RELAY_ROOT || "https://dev-pedw-ns.servicebus.windows.net/dev-pedw-hc/"; export default async function ApiProxy(req, res) { - var contactId = req.query.contactId; - var token = await getToken(); - var data = JSON.stringify(req.body); - var queryUrl = "contacts(" + contactId + ")"; + const contactId = req.query.contactId; - var config = { - method: "patch", - url: WEBAPI_URL + queryUrl + hashAPIPath(queryUrl), - headers: { - "OData-MaxVersion": "4.0", - "OData-Version": "4.0", - "Accept": "application/json", - "Prefer": 'odata.include-annotations="*",return=representation', - "Authorization": "Bearer " + token.access_token, - "Content-Type": "application/json" - }, - data: data - }; - - return axios(config) - .then(({ data }) => { - res.status(200).json(data); - }) - .catch((error) => { - consoleLogger(error); - res.status(400).json(error); + if (typeof contactId !== "string" || contactId.trim().length === 0) { + return respondError(res, { + status: 400, + code: "CONTACT_ID_REQUIRED", + message: "contactId is required" }); + } + + if (!req.body || Object.keys(req.body).length === 0) { + return respondError(res, { + status: 400, + code: "PASSWORD_UPDATE_PAYLOAD_REQUIRED", + message: "Password update payload is required" + }); + } + + try { + const token = await getToken(); + const data = JSON.stringify(req.body); + const queryUrl = "contacts(" + contactId + ")"; + + const config = { + method: "patch", + url: WEBAPI_URL + queryUrl + hashAPIPath(queryUrl), + headers: { + "OData-MaxVersion": "4.0", + "OData-Version": "4.0", + Accept: "application/json", + Prefer: 'odata.include-annotations="*",return=representation', + Authorization: "Bearer " + token.access_token, + "Content-Type": "application/json" + }, + data + }; + + const response = await axios(config); + return respondSuccess(res, response.data); + } catch (error) { + consoleLogger(error); + return respondError(res, { + status: 400, + code: "PASSWORD_UPDATE_FAILED", + message: "Failed to update password" + }); + } } diff --git a/tests/phase21/endpoint-handler-contract.test.cjs b/tests/phase21/endpoint-handler-contract.test.cjs index 2f8ccbed..a85e5ed2 100644 --- a/tests/phase21/endpoint-handler-contract.test.cjs +++ b/tests/phase21/endpoint-handler-contract.test.cjs @@ -442,6 +442,535 @@ test("getemailaccountcheck success returns existing data payload contract", asyn }); }); +test("getwatchedcasesproxy returns LOGGED_IN_USER_ID_REQUIRED when loggedInUserId missing", async () => { + const mod = loadModule("pages/api/endpoint/getwatchedcasesproxy_api.js", { + respondError: respondErrorMock, + respondSuccess: respondSuccessMock, + getToken: async () => ({ access_token: "token" }), + hashAPIPath: () => "&hash=expected", + azureHeaders: () => ({}), + axios: { get: async () => ({ data: { value: [] } }) }, + consoleLogger: () => {} + }); + + const req = { query: {} }; + const res = createRes(); + await mod.default(req, res); + + assert.strictEqual(res.state.statusCode, 400); + assert.strictEqual( + res.state.jsonBody.error.code, + "LOGGED_IN_USER_ID_REQUIRED" + ); +}); + +test("getwatchedcasesproxy catch path returns WATCHED_CASES_PROXY_FETCH_FAILED", async () => { + const mod = loadModule("pages/api/endpoint/getwatchedcasesproxy_api.js", { + respondError: respondErrorMock, + respondSuccess: respondSuccessMock, + getToken: async () => ({ access_token: "token" }), + hashAPIPath: () => "&hash=expected", + azureHeaders: () => ({}), + axios: { + get: async () => { + throw new Error("relay failed"); + } + }, + consoleLogger: () => {} + }); + + const req = { query: { loggedInUserId: "c1" } }; + const res = createRes(); + await mod.default(req, res); + + assert.strictEqual(res.state.statusCode, 400); + assert.strictEqual( + res.state.jsonBody.error.code, + "WATCHED_CASES_PROXY_FETCH_FAILED" + ); +}); + +test("getmyrepresentationsproxy returns LOGGED_IN_USER_ID_REQUIRED when loggedInUserId missing", async () => { + const mod = loadModule( + "pages/api/endpoint/getmyrepresentationsproxy_api.js", + { + respondError: respondErrorMock, + respondSuccess: respondSuccessMock, + getToken: async () => ({ access_token: "token" }), + hashAPIPath: () => "&hash=expected", + azureHeaders: () => ({}), + axios: { get: async () => ({ data: { value: [] } }) }, + consoleLogger: () => {} + } + ); + + const req = { query: {} }; + const res = createRes(); + await mod.default(req, res); + + assert.strictEqual(res.state.statusCode, 400); + assert.strictEqual( + res.state.jsonBody.error.code, + "LOGGED_IN_USER_ID_REQUIRED" + ); +}); + +test("getmyrepresentationsproxy catch path returns MY_REPRESENTATIONS_PROXY_FETCH_FAILED", async () => { + const mod = loadModule( + "pages/api/endpoint/getmyrepresentationsproxy_api.js", + { + respondError: respondErrorMock, + respondSuccess: respondSuccessMock, + getToken: async () => ({ access_token: "token" }), + hashAPIPath: () => "&hash=expected", + azureHeaders: () => ({}), + axios: { + get: async () => { + throw new Error("relay failed"); + } + }, + consoleLogger: () => {} + } + ); + + const req = { query: { loggedInUserId: "c1" } }; + const res = createRes(); + await mod.default(req, res); + + assert.strictEqual(res.state.statusCode, 400); + assert.strictEqual( + res.state.jsonBody.error.code, + "MY_REPRESENTATIONS_PROXY_FETCH_FAILED" + ); +}); + +test("getrepresentationsproxy returns INCIDENT_ID_REQUIRED when incidentID missing", async () => { + const mod = loadModule( + "pages/api/endpoint/getrepresentationsproxy_api.js", + { + respondError: respondErrorMock, + respondSuccess: respondSuccessMock, + getToken: async () => ({ access_token: "token" }), + hashAPIPath: () => "&hash=expected", + azureHeaders: () => ({}), + axios: { get: async () => ({ data: { value: [] } }) }, + consoleLogger: () => {} + } + ); + + const req = { query: {} }; + const res = createRes(); + await mod.default(req, res); + + assert.strictEqual(res.state.statusCode, 400); + assert.strictEqual(res.state.jsonBody.error.code, "INCIDENT_ID_REQUIRED"); +}); + +test("getrepresentationsproxy catch path returns REPRESENTATIONS_PROXY_FETCH_FAILED", async () => { + const mod = loadModule( + "pages/api/endpoint/getrepresentationsproxy_api.js", + { + respondError: respondErrorMock, + respondSuccess: respondSuccessMock, + getToken: async () => ({ access_token: "token" }), + hashAPIPath: () => "&hash=expected", + azureHeaders: () => ({}), + axios: { + get: async () => { + throw new Error("relay failed"); + } + }, + consoleLogger: () => {} + } + ); + + const req = { query: { incidentID: "i1" } }; + const res = createRes(); + await mod.default(req, res); + + assert.strictEqual(res.state.statusCode, 400); + assert.strictEqual( + res.state.jsonBody.error.code, + "REPRESENTATIONS_PROXY_FETCH_FAILED" + ); +}); + +test("getawaitingsubmissionproxy returns LOGGED_IN_USER_ID_REQUIRED when loggedInUserId missing", async () => { + const mod = loadModule( + "pages/api/endpoint/getawaitingsubmissionproxy_api.js", + { + respondError: respondErrorMock, + respondSuccess: respondSuccessMock, + getToken: async () => ({ access_token: "token" }), + hashAPIPath: () => "&hash=expected", + azureHeaders: () => ({}), + axios: { get: async () => ({ data: { value: [] } }) }, + consoleLogger: () => {} + } + ); + + const req = { query: {} }; + const res = createRes(); + await mod.default(req, res); + + assert.strictEqual(res.state.statusCode, 400); + assert.strictEqual( + res.state.jsonBody.error.code, + "LOGGED_IN_USER_ID_REQUIRED" + ); +}); + +test("getawaitingsubmissionproxy catch path returns AWAITING_SUBMISSION_PROXY_FETCH_FAILED", async () => { + const mod = loadModule( + "pages/api/endpoint/getawaitingsubmissionproxy_api.js", + { + respondError: respondErrorMock, + respondSuccess: respondSuccessMock, + getToken: async () => ({ access_token: "token" }), + hashAPIPath: () => "&hash=expected", + azureHeaders: () => ({}), + axios: { + get: async () => { + throw new Error("relay failed"); + } + }, + consoleLogger: () => {} + } + ); + + const req = { query: { loggedInUserId: "c1" } }; + const res = createRes(); + await mod.default(req, res); + + assert.strictEqual(res.state.statusCode, 400); + assert.strictEqual( + res.state.jsonBody.error.code, + "AWAITING_SUBMISSION_PROXY_FETCH_FAILED" + ); +}); + +test("createaccount returns ACCOUNT_PAYLOAD_REQUIRED when body missing", async () => { + const mod = loadModule("pages/api/endpoint/createaccount_api.js", { + respondError: respondErrorMock, + respondSuccess: respondSuccessMock, + getToken: async () => ({ access_token: "token" }), + hashAPIPath: () => "&hash=expected", + axios: async () => ({ data: { contactid: "c1" } }), + consoleLogger: () => {} + }); + + const req = { query: {}, body: undefined }; + const res = createRes(); + await mod.default(req, res); + + assert.strictEqual(res.state.statusCode, 400); + assert.strictEqual( + res.state.jsonBody.error.code, + "ACCOUNT_PAYLOAD_REQUIRED" + ); +}); + +test("createaccount catch path returns ACCOUNT_CREATE_FAILED", async () => { + const mod = loadModule("pages/api/endpoint/createaccount_api.js", { + respondError: respondErrorMock, + respondSuccess: respondSuccessMock, + getToken: async () => ({ access_token: "token" }), + hashAPIPath: () => "&hash=expected", + axios: async () => { + throw new Error("relay failed"); + }, + consoleLogger: () => {} + }); + + const req = { query: {}, body: { firstname: "A" } }; + const res = createRes(); + await mod.default(req, res); + + assert.strictEqual(res.state.statusCode, 400); + assert.strictEqual(res.state.jsonBody.error.code, "ACCOUNT_CREATE_FAILED"); +}); + +test("updateaccount returns CONTACT_ID_REQUIRED when contactId missing", async () => { + const mod = loadModule("pages/api/endpoint/updateaccount_api.js", { + respondError: respondErrorMock, + respondSuccess: respondSuccessMock, + getToken: async () => ({ access_token: "token" }), + hashAPIPath: () => "&hash=expected", + axios: async () => ({ data: { contactid: "c1" } }), + consoleLogger: () => {} + }); + + const req = { query: {}, body: { firstname: "A" } }; + const res = createRes(); + await mod.default(req, res); + + assert.strictEqual(res.state.statusCode, 400); + assert.strictEqual(res.state.jsonBody.error.code, "CONTACT_ID_REQUIRED"); +}); + +test("updateaccount returns ACCOUNT_UPDATE_PAYLOAD_REQUIRED when body missing", async () => { + const mod = loadModule("pages/api/endpoint/updateaccount_api.js", { + respondError: respondErrorMock, + respondSuccess: respondSuccessMock, + getToken: async () => ({ access_token: "token" }), + hashAPIPath: () => "&hash=expected", + axios: async () => ({ data: { contactid: "c1" } }), + consoleLogger: () => {} + }); + + const req = { query: { contactId: "c1" }, body: undefined }; + const res = createRes(); + await mod.default(req, res); + + assert.strictEqual(res.state.statusCode, 400); + assert.strictEqual( + res.state.jsonBody.error.code, + "ACCOUNT_UPDATE_PAYLOAD_REQUIRED" + ); +}); + +test("updateaccount catch path returns ACCOUNT_UPDATE_FAILED", async () => { + const mod = loadModule("pages/api/endpoint/updateaccount_api.js", { + respondError: respondErrorMock, + respondSuccess: respondSuccessMock, + getToken: async () => ({ access_token: "token" }), + hashAPIPath: () => "&hash=expected", + axios: async () => { + throw new Error("relay failed"); + }, + consoleLogger: () => {} + }); + + const req = { query: { contactId: "c1" }, body: { firstname: "A" } }; + const res = createRes(); + await mod.default(req, res); + + assert.strictEqual(res.state.statusCode, 400); + assert.strictEqual(res.state.jsonBody.error.code, "ACCOUNT_UPDATE_FAILED"); +}); + +test("updatepassword returns CONTACT_ID_REQUIRED when contactId missing", async () => { + const mod = loadModule("pages/api/endpoint/updatepassword_api.js", { + respondError: respondErrorMock, + respondSuccess: respondSuccessMock, + getToken: async () => ({ access_token: "token" }), + hashAPIPath: () => "&hash=expected", + axios: async () => ({ data: { contactid: "c1" } }), + consoleLogger: () => {} + }); + + const req = { query: {}, body: { pinswg_password: "abc" } }; + const res = createRes(); + await mod.default(req, res); + + assert.strictEqual(res.state.statusCode, 400); + assert.strictEqual(res.state.jsonBody.error.code, "CONTACT_ID_REQUIRED"); +}); + +test("updatepassword returns PASSWORD_UPDATE_PAYLOAD_REQUIRED when body missing", async () => { + const mod = loadModule("pages/api/endpoint/updatepassword_api.js", { + respondError: respondErrorMock, + respondSuccess: respondSuccessMock, + getToken: async () => ({ access_token: "token" }), + hashAPIPath: () => "&hash=expected", + axios: async () => ({ data: { contactid: "c1" } }), + consoleLogger: () => {} + }); + + const req = { query: { contactId: "c1" }, body: undefined }; + const res = createRes(); + await mod.default(req, res); + + assert.strictEqual(res.state.statusCode, 400); + assert.strictEqual( + res.state.jsonBody.error.code, + "PASSWORD_UPDATE_PAYLOAD_REQUIRED" + ); +}); + +test("updatepassword catch path returns PASSWORD_UPDATE_FAILED", async () => { + const mod = loadModule("pages/api/endpoint/updatepassword_api.js", { + respondError: respondErrorMock, + respondSuccess: respondSuccessMock, + getToken: async () => ({ access_token: "token" }), + hashAPIPath: () => "&hash=expected", + axios: async () => { + throw new Error("relay failed"); + }, + consoleLogger: () => {} + }); + + const req = { + query: { contactId: "c1" }, + body: { pinswg_password: "abc" } + }; + const res = createRes(); + await mod.default(req, res); + + assert.strictEqual(res.state.statusCode, 400); + assert.strictEqual(res.state.jsonBody.error.code, "PASSWORD_UPDATE_FAILED"); +}); + +test("getbasicsearch returns SEARCH_STRING_REQUIRED when searchString missing", async () => { + const mod = loadModule("pages/api/endpoint/getbasicsearch_api.js", { + respondError: respondErrorMock, + respondSuccess: respondSuccessMock, + getToken: async () => ({ access_token: "token" }), + hashAPIPath: () => "&hash=expected", + azureHeadersPaged: () => ({}), + axios: { get: async () => ({ data: { value: [] } }) }, + consoleLogger: () => {} + }); + + const req = { query: {} }; + const res = createRes(); + await mod.default(req, res); + + assert.strictEqual(res.state.statusCode, 400); + assert.strictEqual(res.state.jsonBody.error.code, "SEARCH_STRING_REQUIRED"); +}); + +test("getbasicsearch catch path returns BASIC_SEARCH_FETCH_FAILED", async () => { + const mod = loadModule("pages/api/endpoint/getbasicsearch_api.js", { + respondError: respondErrorMock, + respondSuccess: respondSuccessMock, + getToken: async () => ({ access_token: "token" }), + hashAPIPath: () => "&hash=expected", + azureHeadersPaged: () => ({}), + axios: { + get: async () => { + throw new Error("relay failed"); + } + }, + consoleLogger: () => {} + }); + + const req = { query: { searchString: "CAS" } }; + const res = createRes(); + await mod.default(req, res); + + assert.strictEqual(res.state.statusCode, 400); + assert.strictEqual( + res.state.jsonBody.error.code, + "BASIC_SEARCH_FETCH_FAILED" + ); +}); + +test("getcasemessage returns CASE_ID_REQUIRED when id missing", async () => { + const mod = loadModule("pages/api/endpoint/getcasemessage_api.js", { + respondError: respondErrorMock, + respondSuccess: respondSuccessMock, + getToken: async () => ({ access_token: "token" }), + hashAPIPath: () => "&hash=expected", + azureHeadersPaged: () => ({}), + axios: { get: async () => ({ data: { value: [] } }) }, + consoleLogger: () => {} + }); + + const req = { query: {} }; + const res = createRes(); + await mod.default(req, res); + + assert.strictEqual(res.state.statusCode, 400); + assert.strictEqual(res.state.jsonBody.error.code, "CASE_ID_REQUIRED"); +}); + +test("getcasemessage catch path returns CASE_MESSAGE_FETCH_FAILED", async () => { + const mod = loadModule("pages/api/endpoint/getcasemessage_api.js", { + respondError: respondErrorMock, + respondSuccess: respondSuccessMock, + getToken: async () => ({ access_token: "token" }), + hashAPIPath: () => "&hash=expected", + azureHeadersPaged: () => ({}), + axios: { + get: async () => { + throw new Error("relay failed"); + } + }, + consoleLogger: () => {} + }); + + const req = { query: { id: "i1" } }; + const res = createRes(); + await mod.default(req, res); + + assert.strictEqual(res.state.statusCode, 400); + assert.strictEqual( + res.state.jsonBody.error.code, + "CASE_MESSAGE_FETCH_FAILED" + ); +}); + +test("getadvancedsearch returns SEARCH_STRING_REQUIRED when searchstring missing", async () => { + const mod = loadModule("pages/api/endpoint/getadvancedsearch_api.js", { + respondError: respondErrorMock, + respondSuccess: respondSuccessMock, + getToken: async () => ({ access_token: "token" }), + hashAPIPath: () => "&hash=expected", + azureHeadersPaged: () => ({}), + axios: { get: async () => ({ data: { value: [] } }) }, + consoleLogger: () => {} + }); + + const req = { query: {} }; + const res = createRes(); + await mod.default(req, res); + + assert.strictEqual(res.state.statusCode, 400); + assert.strictEqual(res.state.jsonBody.error.code, "SEARCH_STRING_REQUIRED"); +}); + +test("getadvancedsearch returns INVALID_SEARCH_STRING when searchstring invalid JSON", async () => { + const mod = loadModule("pages/api/endpoint/getadvancedsearch_api.js", { + respondError: respondErrorMock, + respondSuccess: respondSuccessMock, + getToken: async () => ({ access_token: "token" }), + hashAPIPath: () => "&hash=expected", + azureHeadersPaged: () => ({}), + axios: { get: async () => ({ data: { value: [] } }) }, + consoleLogger: () => {} + }); + + const req = { query: { searchstring: "not-json" } }; + const res = createRes(); + await mod.default(req, res); + + assert.strictEqual(res.state.statusCode, 400); + assert.strictEqual(res.state.jsonBody.error.code, "INVALID_SEARCH_STRING"); +}); + +test("getadvancedsearch catch path returns ADVANCED_SEARCH_FETCH_FAILED", async () => { + const mod = loadModule("pages/api/endpoint/getadvancedsearch_api.js", { + respondError: respondErrorMock, + respondSuccess: respondSuccessMock, + getToken: async () => ({ access_token: "token" }), + hashAPIPath: () => "&hash=expected", + azureHeadersPaged: () => ({}), + axios: { + get: async () => { + throw new Error("relay failed"); + } + }, + consoleLogger: () => {} + }); + + const req = { + query: { + searchstring: encodeURI( + JSON.stringify({ q: "cas", lpa: "l1", apt: "1" }) + ) + } + }; + const res = createRes(); + await mod.default(req, res); + + assert.strictEqual(res.state.statusCode, 400); + assert.strictEqual( + res.state.jsonBody.error.code, + "ADVANCED_SEARCH_FETCH_FAILED" + ); +}); + const run = async () => { let passed = 0; for (const currentTest of tests) {