90 KiB
Portal API Platform Assessment
Status
Assessment-only.
First bounded slice complete:
- Slice A — API Family Classification Sample
No refactor, implementation, or runtime behaviour change was performed.
Required context read
The following files were read before this assessment slice:
context/architecture.mdcontext/portal-api-security-boundary-assessment.mdcontext/integration-map.mdmemory-bank/debt-list.mdmemory-bank/change-log.md
Sample scope
This slice intentionally inspected only the following API areas:
pages/api/endpointpages/api/filepages/api/emailpages/api/documentspages/api/auth
This is not a full route catalogue.
Representative sample files reviewed directly:
pages/api/endpoint/getbasicsearch_api.jspages/api/endpoint/getmycases_api.jspages/api/endpoint/createcase_api.jspages/api/file/getbloblist.jspages/api/file/upload.jspages/api/file/createappealcompletemessage_api.jspages/api/email/notify.jspages/api/email/getall.jspages/api/documents/download/[id].jspages/api/auth/[...nextauth].jspages/api/auth/resolve-locale.js
Supporting bounded inspection also covered:
- top-level file listings for each sampled folder
pages/api/middleware/*- targeted pattern searches inside the sampled folders only
Findings
The sampled API surface already shows a clear split between:
- newer helper-oriented relay handlers
- typically using
relayGet(...) - standard
respondError(...) - explicit required-query validation
- typically using
- older direct integration/orchestration handlers
- typically using
axios(...)directly - constructing CRM relay URLs manually
- invoking
hashAPIPath(...)inline - mixing multiple responsibilities in a single route
- typically using
The sample suggests the platform is not one uniform API layer, but a mixed platform of:
- CRM relay facades
- Azure Storage facades
- queue/finalisation orchestration routes
- GOV.UK Notify routes
- NextAuth/session routes
- a small number of utility/meta helpers
API family classification
1. CRM relay read
Observed sample indicators:
pages/api/endpoint/getbasicsearch_api.jspages/api/endpoint/getmycases_api.js
Characteristics:
- reads CRM data through relay-backed query URLs
- often uses
relayGet(...) - usually validates required query fields first
- may lightly transform CRM results before returning
Assessment classification:
endpoint/is primarily CRM relay read plus some write variants
2. CRM relay write
Observed sample indicators:
pages/api/endpoint/createcase_api.js
Characteristics:
- uses direct
axios(...)with bearer token - constructs CRM URL as
WEBAPI_URL + queryUrl + hashAPIPath(queryUrl) - forwards create/update/patch/delete actions into CRM
Assessment classification:
- part of
endpoint/is CRM relay write
3. storage/blob read
Observed sample indicators:
pages/api/file/getbloblist.js
Characteristics:
- validates
container,casefolderID,hash - verifies request integrity with candidate-path hash comparison
- calls Azure storage helpers such as
getBlobs(...)
Assessment classification:
- part of
file/is storage/blob read
4. storage/blob write
Observed sample indicators:
pages/api/file/upload.js
Characteristics:
- validates upload/body fields and hash
- uses multipart middleware
- writes through Azure storage helpers such as
createBlob(...)/createRepBlob(...)
Assessment classification:
- part of
file/is storage/blob write
5. queue/finalisation
Observed sample indicators:
pages/api/file/createappealcompletemessage_api.js
Characteristics:
- reads and rewrites draft/progress blob state
- updates completion markers
- writes case blobs
- triggers completion/finalisation helper
createCaseCompleteMessage(...) - may also trigger secondary account side effects
Assessment classification:
- part of
file/is queue/finalisation and mixed orchestration
6. email/notification
Observed sample indicators:
pages/api/email/notify.jspages/api/email/getall.js
Characteristics:
- GOV.UK Notify send operations
- some routes also fetch CRM/watchlist/document/event data before building email payloads
- bilingual template selection appears embedded in route logic
Assessment classification:
email/is primarily email/notification- some routes are simple send helpers, others are broader orchestration/batch workflows
7. document download
Observed sample indicators:
pages/api/documents/download/[id].js
Characteristics:
- streams a relay-backed document response
- passes through
id+hash - sets download headers
- redirects to
/filenotavailableon failure
Assessment classification:
documents/is document download
8. auth/session
Observed sample indicators:
pages/api/auth/[...nextauth].jspages/api/auth/resolve-locale.js
Characteristics:
- NextAuth session establishment and callback handling
- verification email send
- locale-aware redirect handling
- CRM-backed preferred-language resolution
Assessment classification:
auth/is primarily auth/session
9. local utility/meta
Observed sample indicators:
pages/api/auth/resolve-locale.js
Characteristics:
- small helper-style route
- returns locale metadata rather than handling a full business operation
Assessment classification:
- some sampled routes behave as local utility/meta, even when they consult CRM
10. middleware/helper
Observed sampled middleware area:
pages/api/middleware/apiResponse.jspages/api/middleware/middleware.jspages/api/middleware/relayForwarding.jspages/api/middleware/relayPolicyPresets.js
Characteristics:
- response envelope helper
- multipart parsing helper
- shared relay forwarding helper
- relay policy presets
Assessment classification:
pages/api/middleware/*is clearly middleware/helper
Integration responsibility map
| Sampled family | Primary responsibility | Backing integration classification |
|---|---|---|
pages/api/endpoint read sample (getbasicsearch_api, getmycases_api) |
CRM query relay | CRM relay-backed |
pages/api/endpoint write sample (createcase_api) |
CRM create/write | CRM relay-backed |
pages/api/file read sample (getbloblist) |
blob listing/read | Azure Storage SDK-backed |
pages/api/file write sample (upload) |
blob upload/write | Azure Storage SDK-backed |
pages/api/file finalisation sample (createappealcompletemessage_api) |
draft/blob + completion + account side effects | mixed/orchestration |
pages/api/email/notify |
outbound transactional email | GOV.UK Notify-backed |
pages/api/email/getall |
CRM/watchlist/document/event aggregation + notify send | mixed/orchestration |
pages/api/documents/download/[id] |
streamed document retrieval via relay | CRM relay-backed |
pages/api/auth/[...nextauth] |
session/auth + verification email | NextAuth-backed with GOV.UK Notify-backed email send and CRM locale lookup |
pages/api/auth/resolve-locale |
locale helper | mixed/orchestration leaning local-only utility with CRM lookup |
pages/api/middleware/* |
shared route support | local-only |
Responsibility notes from the sample
endpoint/is mostly a CRM relay platform family.file/is mostly an Azure Storage platform family, but includes finalisation/orchestration routes that cross into CRM/account workflows.email/is not just a thin Notify wrapper; at least one sampled route is an orchestration layer over CRM + Notify.auth/is centered on NextAuth, but locale and sign-in email behavior pull in CRM and Notify responsibilities.
Repeated patterns observed
Observed only from the bounded sample and targeted searches within sampled folders.
hash validation
Clearly repeated in sampled file/ routes and visible more broadly in sampled-folder searches.
Observed forms:
- candidate path arrays
- raw/encoded path variants
- compare
hashAPIPath(candidatePath)against&hash=or?hash=+ provided hash
Examples:
pages/api/file/getbloblist.jspages/api/file/upload.jspages/api/file/createappealcompletemessage_api.js
signed request helper usage
Observed in the newer relay family through shared helpers rather than inline hash construction.
Examples:
relayGet(...)ingetbasicsearch_api.jsrelayGet(...)ingetmycases_api.js
Assessment note:
- helper usage is present, but not yet universal across sampled families
relay forwarding
Observed strongly in the newer endpoint/ read family.
Characteristics:
relayGet(...)- relay policy preset import
- optional transform step
- structured error envelope
required query validation
Strongly repeated across all sampled families.
Examples:
searchStringrequiredloggedInUserIdrequiredcontainer,casefolderID,hashrequiredid/hashrequired in download flow
response envelope style
Repeated modern pattern:
respondSuccess(...)respondError(...)
Observed across sampled endpoint/file/email routes.
Assessment note:
- response helpers are widespread in the sample even when integration patterns differ underneath
raw CRM URL building
Repeated in older direct-write/orchestration routes.
Examples:
WEBAPI_URL + queryUrl + hashAPIPath(queryUrl)- direct axios config objects with bearer headers
Observed in:
pages/api/endpoint/createcase_api.jspages/api/email/getall.js- visible across targeted searches in multiple sampled folders
Azure blob path construction
Repeated in sampled file/ routes.
Examples:
container+casefolderIDtempCaseRef + "/" + tempCaseRef + "_case.json"- split path handling for representation files using
/
logging style
Mixed styles observed:
- structured-ish redacted
console.info(...)inemail/notify.jsandauth/[...nextauth].js - plain
console.log(...)increatecase_api.jsanddocuments/download/[id].js consoleLogger(...)used for error logging in many routes
Assessment note:
- logging style is visibly inconsistent within the sample
Obvious duplication candidates
These are sample-based family-level observations only. No consolidation is recommended yet.
paged / unpaged endpoint variants
Observed from folder listing and targeted search patterns:
getbasicsearch_api/getbasicsearchpaged_apigetbasicsearchdetails_api/getbasicsearchdetailspaged_apigetadvancedsearch_api/getadvancedsearchpaged_api- document detail/history paged variants
Classification:
- likely intentional
Reason:
- naming and existing contract-hardening history suggest explicit contract variants rather than accidental duplicates
search / detail / history variants
Observed from endpoint/ sample family:
- search results
- detail retrieval
- history retrieval
- document-type retrieval
Classification:
- likely intentional
blob list / download / delete variants
Observed from file/ sample family and listings:
getbloblistdownloadblobdeleteblobdeleteblobcasedeleteblobrep- proxy variants
Classification:
- likely historical
Reason:
- the split between case/rep/proxy variants and repeated hash-validation shapes suggests growth by accretion
create / update / patch CRM wrappers
Observed from endpoint/ and file/ folder listings plus sample:
createcase_apiupdatecase_apipatchcase_apiupdateaccount_apicreateaccount_api
Classification:
- likely historical
Reason:
- similar direct axios + token + hash + relay URL patterns recur across wrappers
email batch / send helpers
Observed from email/ sample:
notify.jsas a focused send routegetall.jsas a broad gather-and-send batch route- related support routes
getdocuments.js,getevents.js,getmailinglist.js,getcaseref.js
Classification:
- unclear
Reason:
- some separation may reflect legitimate batch assembly boundaries, but the family also shows orchestration overlap
Contract-critical families
From the sample, the following families appear contract-critical.
public search
Yes.
Evidence:
getbasicsearch_api.js- search/detail/history family naming in
endpoint/
Why critical:
- public-facing query/filter/result contracts likely feed core search UI behavior
myportal / dashboard
Yes.
Evidence:
getmycases_api.js
Why critical:
- dashboard and authenticated case-list flows depend on these payloads and identifiers
submission / finalisation
Yes.
Evidence:
createappealcompletemessage_api.js
Why critical:
- this looks like a transition point from draft/blob state into completion/finalisation processing
file upload / download
Yes.
Evidence:
upload.jsgetbloblist.js- broader file folder sample
Why critical:
- these routes underpin draft persistence and user document handling
document download
Yes.
Evidence:
documents/download/[id].js
Why critical:
- direct binary/document delivery contract with failure redirect behavior
auth / session
Yes.
Evidence:
auth/[...nextauth].js
Why critical:
- session establishment, callback routing, verification email, and locale-aware redirects are central platform contracts
email / notification
Yes.
Evidence:
email/notify.jsemail/getall.js
Why critical:
- user communications, watchlist notifications, and sign-in email flows depend on these contracts
Risks / cautions
This slice is intentionally high-level and sample-based.
Key cautions:
- Do not over-generalise from one sample per family
- especially in
endpoint/, where newer helper-based routes and older direct axios routes coexist
- especially in
- Integration responsibility is not always single-system
- some routes are clearly orchestration routes rather than thin adapters
- Naming can conceal contract differences
- proxy, paged, history, detail, and case/rep variants may preserve subtle caller expectations
- The sample confirms structural inconsistency, not implementation priority
- this assessment does not yet decide what should be consolidated
- Auth/email boundaries are cross-cutting
auth/[...nextauth].jsis not just auth/session; it also includes Notify and CRM locale lookups
Validation performed
Manual inspection and small targeted searches only.
Performed:
- direct reading of required context files
- small directory listings for:
pages/api/endpointpages/api/filepages/api/emailpages/api/documentspages/api/authpages/api/middleware
- direct bounded file inspection of representative samples only
- targeted pattern searches limited to sampled folders for:
relayGetrespondError/respondSuccesshashAPIPathaxiosNotifyClientgetPortalLogin- locale/redirect handling
Not performed:
- no repo-wide automated analysis
- no bulk inventory generation
- no Python
- no runtime code changes
- no lint/tests, because this slice is documentation-only
Recommendation
Next bounded slice only:
Slice B — Endpoint CRM Relay Shape Sample
Inspect a small representative subset within pages/api/endpoint only, split into:
- public search/read routes
- authenticated myportal read routes
- CRM mutation/write routes
- proxy variants
Goal of Slice B:
- distinguish newer
relayGet(...)handler families from older directaxios + hashAPIPathrelay wrappers - identify the main contract shapes and the most common wrapper patterns inside
endpoint/ - remain classification-only, with no consolidation proposal yet
Slice B — Endpoint CRM Relay Contract Shape Sample
Required context read
The following files were re-read before Slice B:
context/portal-api-platform-assessment.mdcontext/portal-api-security-boundary-assessment.mdcontext/architecture.mdmemory-bank/change-log.md
Sample scope
Slice B intentionally focused only on:
pages/api/endpoint
This remained a representative subset only, not a folder-wide route inventory.
Representative routes reviewed directly:
1. Public read/search
getbasicsearch_api.jsgetbasicsearchpaged_api.jsgetadvancedsearch_api.jsgetsearchdocumentdetails_api.jsgetsearchdocumenthistory_api.js
2. Authenticated/myportal read
getmycases_api.jsgetmyrepresentations_api.jsgetwatchedcases_api.jsgetawaitingsubmission_api.jsgetpersonalaccount_api.js
3. CRM create/write
createcase_api.jscreateaccount_api.jscreatewatchedcases_api.js
4. CRM update/patch/delete
updateaccount_api.jspatchcase_api.jsdeletewatchedcases_api.jsdeletemyrepresentations_api.js
5. Proxy/pass-through or legacy variants
getwatchedcasesproxy_api.js
Supporting bounded inspection also included targeted endpoint-only searches for:
relayGet(...)relayGetData(...)axios(...)hashAPIPath(...)respondError(...)/respondSuccess(...)transformData@odata.nextLink- common explicit status codes
Findings
The sampled pages/api/endpoint family appears to collapse into a modest number of repeated contract shapes even though the implementation layer is mixed.
The clearest split is:
- newer helper-oriented relay read contracts
- structured request guards
relayGet(...)- shared response helper usage
- optional
transformData - optional relay policy presets
- older direct-wrapper mutation contracts
getToken()- manual
queryUrl - direct
axios(config) WEBAPI_URL + queryUrl + hashAPIPath(queryUrl)- explicit method-specific config for create/update/delete
The sample suggests the endpoint layer is not dominated by many bespoke business contracts.
Instead, it looks like a relatively small set of repeated relay contract shapes with route-by-route variations in:
- validation breadth
- transforms
- pagination options
- identifier type
- whether the route is read vs write vs delete
Endpoint contract shapes
A. Public CRM read
Observed sample routes:
getbasicsearch_api.jsgetbasicsearchpaged_api.jsgetadvancedsearch_api.jsgetsearchdocumentdetails_api.jsgetsearchdocumenthistory_api.js
Observed shape:
query params
→ CRM relay read
→ optional transform / pagination normalization
→ response
Characteristics:
- public-style filter or lookup params
- no route-local session enforcement visible
- usually
relayGet(...) - often optional transform stage
- often
@odata.nextLinknormalization for paged families
B. User-owned CRM read
Observed sample routes:
getmycases_api.jsgetmyrepresentations_api.jsgetwatchedcases_api.jsgetawaitingsubmission_api.jsgetpersonalaccount_api.js
Observed shape:
contact/user identifier
→ CRM relay read
→ optional transform
→ response
Characteristics:
- caller supplies
loggedInUserIdorcontactid - route validates identifier presence
- route forwards CRM query via
relayGet(...) - some routes enrich/flatten CRM response before return
C. CRM create
Observed sample routes:
createcase_api.jscreateaccount_api.js
Observed shape:
payload + identifiers
→ CRM create
→ optional side effects
→ response
Characteristics:
req.bodyplus required identifiers- manual relay URL construction
- direct bearer-token axios config
- response typically passes upstream CRM response through
respondSuccess(...) - some routes add secondary side effects (
createcase_api.jsalso writes a case blob)
D. CRM update/patch
Observed sample routes:
updateaccount_api.jspatchcase_api.js
Observed shape:
record identifier + payload or patch intent
→ CRM patch/update
→ response
Characteristics:
- single record identifier in query
- patch body either supplied directly or built in-route
- direct
axios(config)with hashed relay URL
E. CRM delete
Observed sample routes:
deletewatchedcases_api.jsdeletemyrepresentations_api.js
Observed shape:
record identifier
→ CRM delete
→ response
Characteristics:
- single record identifier required
- direct
axios(config)delete - same manual hashed relay URL pattern as create/update wrappers
F. Proxy/pass-through
Observed sample routes:
getwatchedcasesproxy_api.js
Observed shape:
caller request
→ relay-backed wrapper
→ optional transform
→ response
Characteristics:
- structurally very close to corresponding non-proxy read route
- often preserves nearly identical query and transform logic
- main distinction is naming/contract boundary rather than drastically different internal shape
G. Lookup/config/support
Observed indirectly in sample and endpoint-only search evidence:
- account/login/config/lookup families such as
getaccounts_api.js,getpreferredlanguage_api.js,getappealtypes_api.js,getformdata_api.js
Observed shape:
lookup key or config selector
→ CRM option/config/query
→ response
Characteristics:
- frequently helper-oriented
relayGet(...) - lighter transforms than search/myportal routes
- often shared response helper/error contracts
H. Upsert/orchestration hybrid
Observed sample route:
createwatchedcases_api.js
Observed shape:
payload bindings
→ pre-check / existence lookup
→ create or patch decision
→ CRM write
→ response
Characteristics:
- not a pure create route
- combines a read-style pre-check (
relayGetData(...)) with a write-style direct axios relay call - looks like a distinct hybrid contract shape inside
endpoint/
Implementation style map
Newer helper-oriented routes
Strongly represented by sampled public reads, myportal reads, and many proxy/read families.
Typical characteristics:
relayGet(...)- sometimes
relayGetData(...)for supplementary lookups respondError(...)used for input guards- shared
errorResponseobject passed to relay helper - optional
transformData - optional relay policy preset import
- optional header-builder injection for paged/custom reads
Sample examples:
getbasicsearch_api.jsgetbasicsearchpaged_api.jsgetadvancedsearch_api.jsgetsearchdocumentdetails_api.jsgetsearchdocumenthistory_api.jsgetmycases_api.jsgetmyrepresentations_api.jsgetwatchedcases_api.jsgetawaitingsubmission_api.jsgetpersonalaccount_api.jsgetwatchedcasesproxy_api.js
Older direct-wrapper routes
Strongly represented by sampled create/update/delete families.
Typical characteristics:
- direct
axios(config) - explicit
getToken()call - manual
queryUrl - manual
WEBAPI_URL + queryUrl + hashAPIPath(queryUrl)construction - method-specific config (
post,patch,delete) - direct upstream response passthrough via
respondSuccess(...)
Sample examples:
createcase_api.jscreateaccount_api.jsupdateaccount_api.jspatchcase_api.jsdeletewatchedcases_api.jsdeletemyrepresentations_api.js
Hybrid routes
Observed route:
createwatchedcases_api.js
Typical characteristics:
- combines helper-oriented pre-check (
relayGetData) with direct-wrapper mutation (axios + hashAPIPath) - performs route-local branching between
postandpatch
Contract consistency findings
Request parameter style
Observed pattern:
- generally explicit and route-local
- mostly query-string driven for reads and record-targeted mutations
- body + query combination common for create/update routes
Assessment:
- partially consistent
- parameter naming still varies by route family (
searchString,searchstring,loggedInUserId,contactid,contactId,incidentid,watchedCaseID,myRepresentationsID)
Response envelope style
Observed pattern:
respondError(...)andrespondSuccess(...)are broadly used across both newer and older implementations
Assessment:
- more consistent than implementation style
- shared response helpers appear to be a stronger common contract layer than the underlying integration code
Error handling
Observed pattern:
- required-input guards often return
400 - route-level catch blocks usually convert failures to route-specific coded
400 - some non-sampled evidence in the folder shows occasional
404and405
Assessment:
- generally consistent at a high level
- but status-code precision is not fully uniform across the folder
Status codes
Observed sample emphasis:
400dominates for missing input and upstream failure handling- endpoint-only searches show some explicit
404and405usage in other route types
Assessment:
- mostly normalized but not fully uniform
- the sampled create/update/delete routes all converge heavily on
400
Logging
Observed pattern:
- helper-oriented read routes often avoid explicit in-route logging except for special enrichment failures
- older direct-wrapper routes commonly call
consoleLogger(error)in catch blocks - some routes retain more bespoke logging around supplementary sub-queries
Assessment:
- mixed
- logging is more consistent in direct-wrapper mutations than in complex read/orchestration routes
Transforms
Observed pattern:
- common in read families
- used for:
- title projection
- flattening/expanding related CRM objects
- hash-link enrichment
- document-date fallback
@odata.nextLinknormalization- post-filter enrichment for advanced search
Assessment:
- transform-heavy read contracts are a real recurring shape
- not every read route is a thin pass-through
Pagination handling
Observed pattern:
- paged search/document families require extra params such as
orderby,fieldSort,showNumberOfRecords @odata.nextLinknormalization is repeatedly applied- paged headers are injected through custom request option builders
Assessment:
- paged read is a distinct repeated contract variant, not just a small option on base reads
Hash/signing assumptions
Observed pattern:
- helper-oriented reads generally hide relay signing behind shared helper layers
- older mutations perform route-local
hashAPIPath(queryUrl)construction directly - some support/lookup routes such as
getportallogin_api.jsvisibly validate caller-provided hash input before relay read
Assessment:
- signing assumptions are structurally inconsistent across shapes
- read families usually abstract signing away; direct write/delete families usually expose it explicitly in route code
Rationalisation insight
Evidence from the sample suggests:
- few repeated contract shapes
More specifically:
- the folder appears to contain a large number of routes
- but many of those routes seem to fit into a comparatively small number of recurring patterns:
- public CRM read
- user-owned CRM read
- paged read variant
- config/lookup read
- CRM create
- CRM patch/update
- CRM delete
- proxy/pass-through
- hybrid upsert/orchestration
So the route count likely overstates the number of distinct underlying contract shapes.
Contract-critical cautions
The following sampled contract shapes look high-risk to change.
Public search/read
High caution.
Reason:
- public-facing search and document contracts likely drive multiple search and case-view experiences
- paged/unpaged variants may have frontend expectations around filtering,
@odata.nextLink, ordering, and transformed fields
Myportal/dashboard reads
High caution.
Reason:
- these contracts appear central to dashboard, watched-case, representation, and awaiting-submission views
- transforms such as
pinswg_title, watched-case flattening, and title projection may be relied upon directly by callers
Account/profile reads
High caution.
Reason:
getpersonalaccount_api.jsis a small route shape but contract-critical because it likely underpins profile bootstrap and account editing journeys
Case creation/update
High caution.
Reason:
- create/update routes use older direct wrappers and sometimes carry side effects beyond the CRM write itself
createcase_api.jsis especially sensitive because it combines CRM write with blob-side persistence work
Deletion routes
High caution.
Reason:
- delete contracts are simple in visible shape but operationally sensitive
- they rely on record identifiers and direct CRM deletion wrappers
Proxy variants
Medium-high to high caution.
Reason:
- proxy variants often look almost identical to primary routes, which suggests they may exist for compatibility or caller-specific contract reasons rather than redundancy alone
Risks / cautions
- Sample bias remains real
- this slice still used a bounded subset, not all endpoint handlers
- Read routes are not all equally simple
- some helper-based reads are effectively mini-orchestration routes because transforms and supplementary lookups are embedded in them
- Route count may exaggerate uniqueness
- many files appear to be repeated contract variants rather than genuinely new platform shapes
- Implementation age and contract shape are related but not identical
- newer helper-based reads and older direct-wrapper writes are dominant patterns, but hybrid routes like
createwatchedcases_api.jsshow overlap
- newer helper-based reads and older direct-wrapper writes are dominant patterns, but hybrid routes like
- Security-boundary concerns should not be conflated with this slice
- Slice B is about platform contract shapes and maintainability patterns, even though the sampled user-owned routes still expose the previously documented identifier-trust model
Validation performed
Manual inspection and bounded searches only.
Performed:
- re-read required Slice B context files
- direct inspection of a representative endpoint-only subset across:
- public read/search
- authenticated/myportal read
- CRM create
- CRM update/patch/delete
- proxy/pass-through
- targeted endpoint-only searches for:
relayGet(...)relayGetData(...)axios(...)hashAPIPath(...)respondSuccess(...)/respondError(...)transformData@odata.nextLink- explicit status code patterns
Not performed:
- no full endpoint inventory
- no repo-wide automated analysis
- no Python
- no runtime code changes
- no lint/tests, because this remains documentation-only assessment work
Recommendation
Next bounded slice only:
Slice C — Endpoint Transform and Pagination Pattern Sample
Restrict scope to a representative subset of pages/api/endpoint routes that use:
transformData@odata.nextLinknormalization- paged/unpaged route pairs
- supplementary
relayGetData(...)enrichment
Goal:
- determine whether transform/pagination behavior itself collapses into a small number of reusable contract sub-patterns
- stay assessment-only
- do not propose implementation yet
Slice C — API Maintenance Map & Reuse Baseline
Required context read
The following files were read before Slice C:
context/portal-api-platform-assessment.mdcontext/architecture.mdcontext/integration-map.mdmemory-bank/debt-list.mdmemory-bank/change-log.md
Findings
The current API surface appears maintainable only with prior local knowledge because folder responsibility and naming have drifted over time.
The strongest current maintenance pattern is:
pages/api/endpointis still the main historical CRM relay catch-all- later folders (
file,email,documents,auth,admin) were added for newer needs - but those later folders are not purely technical or domain-clean boundaries
The result is a maintenance problem of findability first, consistency second:
- a developer must often know the history of the route family to know where to look
- once found, they must still determine whether the family uses newer shared helpers or older direct wrappers
The codebase does already contain reusable API building blocks, but they are not yet expressed in one obvious maintenance navigation model.
Folder Responsibility Map
pages/api/endpoint
- Intended responsibility if visible: general portal business-data APIs via CRM relay
- Actual responsibility based on sampled evidence: broad catch-all for CRM reads, account/profile support, portal user reads, public search, document metadata, lookup/config, and many create/update/delete mutation wrappers
- Does folder naming still match responsibility? partially
- Assessment: mixed / historical
Maintenance note:
- this is still the first place to look for most CRM-backed portal behavior
- but it is too broad to communicate ownership clearly by folder name alone
pages/api/file
- Intended responsibility if visible: file/blob/document upload/download operations
- Actual responsibility based on sampled evidence: Azure Storage blob operations, uploads, draft reads, delete/download/list flows, generated PDFs, finalisation routes, some queue/completion work, and some CRM-adjacent orchestration/involvement routes
- Does folder naming still match responsibility? only partially
- Assessment: mixed
Maintenance note:
- a developer working on drafts/submission may need this folder even when the main change is not “just files”
pages/api/email
- Intended responsibility if visible: email and notification handling
- Actual responsibility based on sampled evidence: direct Notify send, mailing list/event/document gathering, watchlist notification batch assembly, and CRM-backed orchestration before send
- Does folder naming still match responsibility? partially
- Assessment: mixed
Maintenance note:
- some email routes are thin notification endpoints, others are multi-step orchestration routes
pages/api/documents
- Intended responsibility if visible: document download
- Actual responsibility based on sampled evidence: essentially a narrow direct document download proxy family
- Does folder naming still match responsibility? yes
- Assessment: coherent
Maintenance note:
- the folder is clear, but broader document-related behavior is still split across
documents,endpoint, andfile
pages/api/auth
- Intended responsibility if visible: authentication/session routes
- Actual responsibility based on sampled evidence: NextAuth boundary plus locale-resolution/auth-support logic with CRM preferred-language lookup and Notify email behavior
- Does folder naming still match responsibility? yes, mostly
- Assessment: acceptable
Maintenance note:
- coherent enough for findability, but auth behavior still crosses into CRM and Notify concerns
pages/api/admin
- Intended responsibility if visible: admin/internal reporting routes
- Actual responsibility based on sampled evidence: administrative CRM reporting/read APIs, including status counts, latest documents, and new-appeal reporting-style queries
- Does folder naming still match responsibility? yes
- Assessment: coherent
Maintenance note:
- this folder looks like one of the clearest top-level API ownership areas
pages/api/middleware
- Intended responsibility if visible: shared API support utilities
- Actual responsibility based on sampled evidence: response envelopes, multipart parsing, shared relay forwarding, relay retry/timeouts/policy presets
- Does folder naming still match responsibility? yes
- Assessment: coherent
Maintenance note:
- this folder already contains some of the strongest reuse primitives for future API work
Top-level utility API files
Reviewed/observed:
pages/api/health.jspages/api/doc.tspages/api/notices/index.js
Assessment:
- Intended responsibility: utility/meta/support endpoints
- Actual responsibility: health/status, swagger/openapi docs, static notice feed
- Does naming still match? mostly yes
- Assessment: coherent for utility/meta
Maintenance note:
- these files are easy to find, but they sit alongside folders in a way that reinforces the overall mixed top-level structure
Feature-to-API Maintenance Map
| Feature area | Likely API folder(s) | Likely route family names | Integration touched | Contract-critical? | Folder fit |
|---|---|---|---|---|---|
| public search | endpoint |
getbasicsearch*, getadvancedsearch*, getbasicdnssearch* |
CRM relay | yes | acceptable |
| advanced/address search | endpoint |
getadvancedsearch*, getbasicsearch_by_address_api, getbasicsearch_by_lparref_api |
CRM relay | yes | acceptable |
| case details | endpoint |
getcase*, getincidentbyid_api, getcasemessage_api, getlinkedcases_api |
CRM relay | yes | acceptable |
| document download | documents, endpoint, file |
documents/download/[id], getsearchdocumentdetails*, getsearchdocumenthistory*, blob download routes |
CRM relay, Azure Storage | yes | confusing |
| my portal dashboard | endpoint, file |
getmycases_api, getmyrepresentations_api, getwatchedcases_api, getawaitingsubmission_api, draft blob reads |
CRM relay, Azure Storage | yes | acceptable |
| watched cases | endpoint |
getwatchedcases*, createwatchedcases_api, deletewatchedcases* |
CRM relay | yes | good |
| representations | endpoint, file |
getrepresentations*, getmyrepresentations*, representation involvement/completion routes |
CRM relay, Azure Storage | yes | acceptable |
| new appeal drafts | file |
getprogressobjblob, getbloblist, upload*, deleteblobcase, setupcontainer |
Azure Storage | yes | acceptable |
| representation drafts | file |
getrepsblob*, upload*, deleteblobrep, editRepJson |
Azure Storage | yes | acceptable |
| appeal submission/finalisation | file, endpoint |
createappealcompletemessage*, createcase_api, patchcase_api, updatecase_api |
Azure Storage, Azure Queue, CRM relay | yes | historical/unclear |
| representation submission/finalisation | file, endpoint |
createrepcompletemessage_api, involvement routes, representation delete/update families |
Azure Storage, Azure Queue, CRM relay | yes | historical/unclear |
| account registration | endpoint, auth |
createaccount_api, getemailaccountcheck_api, getportallogin_api |
CRM relay, NextAuth | yes | acceptable |
| personal details/account update | endpoint |
getpersonalaccount_api, updateaccount_api, updatepassword_api |
CRM relay | yes | acceptable |
| authentication/sign-in | auth, endpoint |
[...nextauth], resolve-locale, getportallogin_api, getpreferredlanguage_api |
NextAuth, GOV.UK Notify, CRM relay | yes | confusing |
| email/notifications | email, auth |
notify, getall, getdocuments, getevents, next-auth verification email flow |
GOV.UK Notify, CRM relay | yes | acceptable |
| admin/internal reporting | admin, endpoint |
getnewappeals_api, getlatestdocuments_api, status-count routes |
CRM relay | no/mostly internal | good |
Folder Drift / Naming Drift
Observed maintenance drift areas:
CRM routes living under file
Examples from existing sampled evidence:
- involvement creation routes
- completion/finalisation routes
- case-related orchestration in
file
Why it affects maintenance:
- a developer may not think to search
file/when the change is really about case submission, involvement, or CRM completion side effects
Orchestration routes living under email
Example:
pages/api/email/getall.js
Why it affects maintenance:
- the route is not just “send an email”; it assembles CRM/watchlist/document/event data before notification send
Document behavior split across endpoint, documents, and file
Examples:
documents/download/[id].js- search document metadata under
endpoint - blob document/file flows under
file
Why it affects maintenance:
- developers must know whether they are dealing with published CRM-backed document retrieval, draft/blob files, or a direct download proxy before they know where to look
Finalisation routes under file
Examples:
createappealcompletemessage_api.jscreaterepcompletemessage_api.js
Why it affects maintenance:
- these are not merely file operations; they sit near a business transition boundary from draft to submitted state
Account/auth-support routes under endpoint
Examples:
getportallogin_api.jsgetpreferredlanguage_api.jsgetemailaccountcheck_api.jsgetpersonalaccount_api.js
Why it affects maintenance:
- account and auth-adjacent responsibilities are split between
auth/andendpoint/, which weakens findability
Historical naming conventions
Examples:
_apisuffix routesproxyvariantspagedvariantsdetails/history/Typesvariants
Why it affects maintenance:
- naming often reflects historical delivery slices more than current ownership boundaries
- similar names can hide materially different caller expectations or integration behavior
Common Building Blocks
relayGet(...)
- What it standardizes: CRM relay GET forwarding, token/header/hash handling, success response path, error response path, optional transforms
- Where it is already used: widely across
pages/api/endpoint/**, especially read families - Preferred for future work? yes, for new CRM read APIs where the route fits the shared relay-read model
- Do legacy alternatives still exist? yes, many older direct axios wrappers remain
relayGetData(...)
- What it standardizes: relay-backed data fetches for sub-queries or enrichments without directly writing to
res - Where it is already used: complex endpoint reads and hybrids such as advanced search enrichment, address/LPA lookups,
createwatchedcases_api.js - Preferred for future work? yes, where a route needs supplementary relay reads inside orchestration logic
- Do legacy alternatives still exist? yes, direct
axios.get(WEBAPI_URL + queryUrl + hashAPIPath(queryUrl))
respondSuccess(...) / respondError(...)
- What they standardize: top-level JSON response conventions and coded error envelopes
- Where they are already used: broadly across endpoint, file, email, admin, and middleware-aware routes
- Preferred for future work? yes
- Do legacy alternatives still exist? yes, some raw
res.status(...).json(...)patterns still exist in the wider API surface and utility endpoints
Relay policy presets
- What they standardize: retry/timeout profiles for read families (
STRICT_LOGIN,LOOKUP,BOUNDED_READ,SEARCH_PAGED) - Where they are already used: many
endpointread routes - Preferred for future work? yes, where relay-backed reads need an existing policy profile
- Do legacy alternatives still exist? yes, older routes without policy presets and direct axios wrappers
signedRequestClient helpers
- What they standardize: signed GET/POST/DELETE execution using existing hashed URL generation
- Where they are already used: service/client layer rather than route layer (
actions/clients/signedRequestClient.js) - Preferred for future work? likely yes for new signed client/service flows
- Do legacy alternatives still exist? yes, many inline
buildHashedQueryUrland direct request patterns remain outside or beneath this layer
Hash/path validation helpers
- What they standardize: HMAC path signing and validation expectations (
hashAPIPath(...), signed URL generation) - Where they are already used: widespread across relay and file/blob flows
- Preferred for future work? yes, where existing signed route models must be preserved
- Do legacy alternatives still exist? yes, many route-local manual candidate-path checks and inline hash construction blocks
Azure storage helpers
- What they standardize: blob/container/queue operations and related metadata assembly
- Where they are already used:
pages/api/file/**, some endpoint/file orchestration flows, service layer helpers - Preferred for future work? yes for storage-facing work
- Do legacy alternatives still exist? some routes still mix storage helpers with route-local orchestration logic rather than remaining thin wrappers
Notify helpers / Notify integration patterns
- What they standardize: currently more implicit than explicit; direct Notify client usage exists, but some shared behavior lives in service modules and auth flow
- Where they are already used:
pages/api/email/**,pages/api/auth/[...nextauth].js, service layer - Preferred for future work? partially; direct Notify usage is established, but orchestration should be chosen deliberately
- Do legacy alternatives still exist? yes, thin send routes and broad orchestration routes coexist
Auth/session helpers
- What they standardize: session establishment primarily via NextAuth route; locale support via
resolve-locale; broader auth-context helpers live outsidepages/api - Where they are already used:
pages/api/auth/**, SSR/service layers elsewhere in repo - Preferred for future work? yes for auth-specific work inside existing NextAuth boundary
- Do legacy alternatives still exist? account/auth-support behavior still partly lives under
endpoint/
Logging helpers
- What they standardize:
consoleLogger(...), redaction helper usage, some structured relay logging - Where they are already used: many API routes, especially catch blocks and relay middleware
- Preferred for future work? yes
- Do legacy alternatives still exist? yes, direct
console.log(...)/console.info(...)still exist in sampled folders
Future Consistency Baseline
This is guidance only for future maintainability work, not an implementation mandate.
Suggested baseline:
- new CRM read APIs should prefer shared relay helpers such as
relayGet(...)where the route fits that contract shape - new relay-backed sub-query/enrichment logic should prefer existing helper-style relay fetches rather than bespoke inline wrappers where suitable
- new JSON responses should prefer
respondSuccess(...)/respondError(...) - new storage-facing APIs should reuse existing Azure storage helpers and established hash-validation patterns
- new Notify-facing APIs should keep thin send routes thin, and only mix broader orchestration where there is a clear need
- new APIs should make it easier to identify:
- owning feature area
- integration touched
- whether the route is contract-critical
- existing direct
axios + hashAPIPathwrappers may remain where behaviour is stable, but they should not be copied blindly into new work when shared helper patterns already exist - future API additions should aim to improve findability as well as technical consistency, so developers can more quickly identify the right folder and family before editing
Maintenance Pain Points
The main maintenance pain points visible in this slice are:
Route findability
- similar behavior is split across multiple top-level folders
- some folders are historical rather than cleanly responsibility-based
Route name similarity
- many near-identical names (
proxy,paged,details,history,_api) increase scan cost
Folder responsibility overlap
- CRM behavior exists in
endpoint,file,email,auth, andadmin - document behavior exists in
endpoint,documents, andfile
Mixed integration responsibilities
- some folders contain thin wrappers, others contain orchestration routes that cross CRM/storage/Notify boundaries
Older/newer implementation styles
- helper-oriented relay contracts and older direct wrappers coexist, so developers must determine style before making even a small change
Missing route ownership documentation
- a future contributor often has to infer “owning feature” from names and code shape rather than from explicit maintenance guidance
Repeated boilerplate and historical growth
- even where shared helpers now exist, route families still show signs of incremental historical accretion
Risks / Cautions
- This is still a bounded maintenance assessment
- it is not a full route inventory or migration plan
- Folder drift does not automatically mean incorrect architecture
- some historical placements may still reflect practical delivery constraints or compatibility concerns
- Reuse guidance should not erase contract-specific nuance
- some route families genuinely need transforms, enrichments, or special caller behavior
- Findability and consistency are related but different problems
- a route can be technically well-structured yet still be hard to find in the current folder layout
- Legacy patterns should be treated carefully
- older direct wrappers are not automatically wrong; the main risk is copying them forward uncritically for new work
Validation performed
Manual inspection and bounded searches only.
Performed:
- re-read required Slice C context files
- small top-level API listings for:
pages/apipages/api/admin
- direct representative inspection of:
- admin routes
- top-level utility/meta routes
- shared middleware/support files
- existing shared client/helper files
- previously reviewed assessment evidence from Slices A and B
- targeted searches for existing building blocks and helper usage across
pages/api
Not performed:
- no repo-wide automated analysis
- no Python
- no bulk route inventory generation
- no runtime code changes
- no lint/tests, because this remains documentation-only assessment work
Recommendation
Next bounded assessment step only:
Slice D — API Route Ownership & Change-Entry Sample
Focus on a bounded set of high-value feature journeys and trace:
- first likely API entry points a maintainer would touch
- adjacent supporting routes/helpers they would also need to inspect
- the minimum “change entry set” for safe edits
Suggested bounded feature sample:
- watched cases
- account/personal details
- public document retrieval
- appeal submission/finalisation
Goal:
- make future change entry points more explicit without proposing refactor yet
Slice D — API Route Ownership & Change-Entry Sample
Required context read
The following files were re-read before Slice D:
context/portal-api-platform-assessment.mdcontext/architecture.mdcontext/integration-map.mdmemory-bank/change-log.md
Findings
For the sampled journeys, the main maintainer problem is not usually “what does this one route do?” but rather:
which UI entry point started this journey,
which service helper actually owns the API call,
which route performs the final contract,
and which adjacent state/helpers must also be checked before changing behaviour?
The four sampled journeys differ in complexity:
- watched cases = feature-led CRM relay journey with several UI entry points
- account/personal details = account/profile journey split across SSR/page state and CRM update APIs
- public document retrieval = public search-driven document metadata + download proxy journey
- appeal submission/finalisation = orchestration-heavy draft-to-submission journey crossing storage, queue/finalisation, and CRM mutation boundaries
Journey Change-Entry Sets
1. Watched cases
Primary UI/component entry points
components/search/searchresults.jscomponents/search/addresssearchresults.jscomponents/search/dnssearchresults.jscomponents/case/summary.jscomponents/myportal/topthree.jscomponents/myportal/viewall.js
Likely service helpers
actions/services/portalDirectService.jsgetWatchedCasesgetWatchedCasesProxycreateWatchedCasesdeleteWatchedCases
API routes
pages/api/endpoint/getwatchedcases_api.jspages/api/endpoint/getwatchedcasesproxy_api.jspages/api/endpoint/createwatchedcases_api.jspages/api/endpoint/deletewatchedcases_api.jspages/api/endpoint/deletewatchedcasesproxy_api.jsas adjacent compatibility variant
Shared clients/helpers
relayGet(...)relayGetData(...)respondError(...)/respondSuccess(...)- relay policy presets
hashAPIPath(...)- route/query builders in portal services
splitWatchedCasesBySubmissionState(...)getDetailsProxy(...)
State/store modules
store/watchedCases/{action,reducer}.jsstore/currentView/action.jsstore/accountDetails/action.js
External integration touched
- CRM relay
- local-only state/helpers
2. Account / personal details
Primary UI/component entry points
pages/account/personaldetails.jscomponents/account/personaldetails.js- adjacent completion/check components referenced there:
components/account/personaldetailsCheck.jscomponents/account/personaldetailsComplete.js
Likely service helpers
actions/services/accountDirectService.jsgetPersonalAccountupdateAccountgetPortalLoginas identity/bootstrap adjacent helper
API routes
pages/api/endpoint/getpersonalaccount_api.jspages/api/endpoint/updateaccount_api.js- adjacent account/auth-support routes often relevant during investigation:
getportallogin_api.jsgetemailaccountcheck_api.jsupdatepassword_api.js
Shared clients/helpers
relayGet(...)respondError(...)/respondSuccess(...)getToken()hashAPIPath(...)- signed request / relay client helpers in the service layer
State/store modules
store/accountDetails/action.jssetAccountDetailssetLoggedInUserId
External integration touched
- CRM relay
- NextAuth (session presence at page level)
- local-only state/helpers
3. Public document retrieval
Primary UI/component entry points
components/search/searchresults.jsand related search flows as user discovery entry points- document metadata/search document routes act as upstream API entry before download
Likely service helpers
actions/services/searchDirectService.jsgetSearchDocumentDetails- related search document retrieval helpers
API routes
pages/api/endpoint/getsearchdocumentdetails_api.jspages/api/endpoint/getsearchdocumentdetailspaged_api.jspages/api/endpoint/getsearchdocumenthistory_api.jspages/api/endpoint/getsearchdocumenthistorypaged_api.jspages/api/endpoint/getsearchdocumentTypes_api.jspages/api/documents/download/[id].js
Shared clients/helpers
relayGet(...)respondError(...)- document hash-link generation logic using HMAC/hash helpers
getToken()inside direct download proxyconsoleLogger(...)
State/store modules
- usually lighter direct store involvement than account/watched cases
- search result/detail state may still be relevant through search result flows
External integration touched
- CRM relay
- local-only helper logic
4. Appeal submission / finalisation
Primary UI/component entry points
pages/myportal/[appealtypes].jsas journey page entrylib/myportal/loadMyPortalAppealPage.jsas key journey loader- adjacent finalisation/completion UI evidence from completion components and journey state transitions
Likely service helpers
actions/services/documentDirectService.jsgetFilesFromBlobgetProgressFromBlobgetAwaitingSubmissionFromBlob
actions/services/accountDirectService.jsgetPersonalAccount
- route-adjacent helpers in storage layer:
actions/azurestorage.js
API routes
pages/api/file/createappealcompletemessage_api.jspages/api/file/createappealcompletemessageproxy_api.jspages/api/endpoint/createcase_api.jspages/api/endpoint/patchcase_api.jspages/api/endpoint/updatecase_api.js- adjacent draft/blob routes usually relevant:
pages/api/file/getbloblist.jspages/api/file/getprogressobjblob.jspages/api/file/upload.jspages/api/file/deleteblobcase.js
Shared clients/helpers
- Azure storage helpers (
getCaseBlob, progress/blob helpers, completion-message helpers) respondError(...)/respondSuccess(...)hashAPIPath(...)relayGet(...)and direct-wrapper mutation patterns- route-builder/signed-request helpers in services
- loader guards in
lib/myportal/loadMyPortalAppealPage.js
State/store modules
store/accountDetails/*store/appealType/*store/currentView/*store/awaitingSubmission/*store/formData/*as adjacent journey support
External integration touched
- Azure Storage
- Azure Queue / completion handoff
- CRM relay
- local-only state/helpers
Route Ownership Classification
Watched cases journey
getwatchedcases_api- feature-owned by watched cases
- integration: CRM relay
getwatchedcasesproxy_api- ambiguous/historical
- integration: CRM relay
createwatchedcases_api- orchestration-owned by watched cases
- integrations: CRM relay, helper/read pre-check
deletewatchedcases_api- feature-owned by watched cases
- integration: CRM relay
deletewatchedcasesproxy_api- ambiguous/historical
- integration: CRM relay
Account / personal details journey
getpersonalaccount_api- feature-owned by account/profile
- integration: CRM relay
updateaccount_api- feature-owned by account/profile
- integration: CRM relay
getportallogin_api- helper/support for account/auth bootstrap
- integration: CRM relay
getemailaccountcheck_api- helper/support for registration/account support
- integration: CRM relay
updatepassword_api- ambiguous/historical in current live account journey terms
- integration: CRM relay
Public document retrieval journey
getsearchdocumentdetails_api- feature-owned by public document retrieval/search detail
- integration: CRM relay
getsearchdocumentdetailspaged_api- feature-owned by public document retrieval/search detail
- integration: CRM relay
getsearchdocumenthistory_api- feature-owned by public document retrieval/history
- integration: CRM relay
getsearchdocumenthistorypaged_api- feature-owned by public document retrieval/history
- integration: CRM relay
getsearchdocumentTypes_api- helper/support for document retrieval/search filtering
- integration: CRM relay
documents/download/[id].js- integration-owned download proxy used by public document retrieval
- integration: CRM relay
Appeal submission / finalisation journey
createappealcompletemessage_api- orchestration-owned by appeal finalisation
- integrations: Azure Storage, Azure Queue/finalisation, CRM/account side effect
createappealcompletemessageproxy_api- helper/support or ambiguous/historical compatibility wrapper
- integrations: local proxy + file/finalisation path
createcase_api- orchestration-owned by appeal submission
- integrations: CRM relay, Azure Storage side effect
patchcase_api- feature-owned by appeal submission/final transition
- integration: CRM relay
updatecase_api- feature-owned by appeal mutation/submission support
- integration: CRM relay
- draft/blob support routes (
getbloblist,getprogressobjblob,upload,deleteblobcase)- integration-owned storage support for the appeal draft/finalisation journey
- integration: Azure Storage
Change Risk Classification
Watched cases
- Risk: high
Reason:
- multiple UI entry points
- CRM read + create/delete paths
- feature state refreshed after mutation
- proxy and non-proxy variants add maintenance ambiguity
Account / personal details
- Risk: high
Reason:
- account/profile contracts are user-critical
- session/bootstrap and CRM profile identity are tightly coupled
- mutation route is simple in code shape but high impact to users
Public document retrieval
- Risk: medium-high
Reason:
- public users are affected directly
- metadata, hash-link generation, and download proxy are split across different areas
- fewer stateful side effects than account/finalisation
Appeal submission / finalisation
- Risk: very high
Reason:
- multiple integrations touched
- orchestration-heavy
- draft/blob + submission transition + finalisation behavior
- contract-critical journey
- state passed across loaders, services, blob data, and CRM write paths
First-Look Checklists
Watched cases
Before changing this journey, inspect:
components/search/searchresults.jsandcomponents/case/summary.jscomponents/myportal/viewall.jsandcomponents/myportal/topthree.jsactions/services/portalDirectService.jswatched-case helperspages/api/endpoint/{getwatchedcases_api,getwatchedcasesproxy_api,createwatchedcases_api,deletewatchedcases_api}.jsstore/watchedCases/*andstore/currentView/*- Slice B / security-boundary notes touching watched-case identifiers in
context/portal-api-platform-assessment.md
Account / personal details
Before changing this journey, inspect:
pages/account/personaldetails.jscomponents/account/personaldetails.jsand adjacent check/complete componentsactions/services/accountDirectService.jspages/api/endpoint/{getpersonalaccount_api,updateaccount_api}.js- adjacent bootstrap/support routes:
getportallogin_api.js,getemailaccountcheck_api.js store/accountDetails/*
Public document retrieval
Before changing this journey, inspect:
- search UI entry points that surface document links
actions/services/searchDirectService.jssearch document helperspages/api/endpoint/{getsearchdocumentdetails_api,getsearchdocumenthistory_api,getsearchdocumentTypes_api}.jspages/api/documents/download/[id].js- any route-local document hash-link generation logic in endpoint/admin/email families
- Slice B findings on public read/document contract shapes
Appeal submission / finalisation
Before changing this journey, inspect:
lib/myportal/loadMyPortalAppealPage.js- the page entry and current appeal/draft UI entry points
actions/services/documentDirectService.jsdraft blob helperspages/api/file/createappealcompletemessage_api.jspages/api/endpoint/{createcase_api,patchcase_api,updatecase_api}.jsactions/azurestorage.jscompletion/blob helpersstore/{appealType,currentView,awaitingSubmission,accountDetails}/*- Slice C maintenance-map notes on finalisation folder drift
Reuse Opportunities
Watched cases
relayGet(...)for read routesrelayGetData(...)for upsert pre-check style behaviorrespondSuccess(...)/respondError(...)- relay policy presets
- logging helpers
- route-builder/query helper patterns in portal services
Account / personal details
relayGet(...)for profile readsrespondSuccess(...)/respondError(...)- token/hash helpers in update flows
- signed/relay client helpers in account service layer
- logging helpers
Public document retrieval
relayGet(...)for document metadata/history readsrespondError(...)-style guard handling- document hash-link generation logic already present in multiple route families
- logging helpers
Appeal submission / finalisation
- Azure storage helpers
respondSuccess(...)/respondError(...)- hash/path validation helpers
- direct-wrapper mutation pattern already established in CRM write routes
- signed request / route builder helpers in service layer
- loader guard patterns in
lib/myportal/loadMyPortalAppealPage.js
Risks / Cautions
- These are first-look entry sets, not exhaustive dependency maps
- each journey has adjacent supporting files beyond what is listed here
- UI entry points are distributed
- watched cases especially can begin from search results, case pages, and myportal views
- Route ownership is sometimes mixed or historical
- proxy and finalisation routes especially need careful interpretation
- Submission/finalisation should be treated as the most sensitive sampled journey
- storage, queue/finalisation, and CRM boundaries all meet there
- Account and watched-case journeys rely on earlier identity/bootstrap context
- a maintainer may need to inspect SSR/session/bootstrap files even when changing a single API route
Validation performed
Manual inspection and bounded searches only.
Performed:
- re-read required Slice D context files
- targeted bounded searches across
components,actions/services,pages,lib, andstorefor the four sampled journeys - direct file inspection of representative first-look journey files including:
components/myportal/viewall.jspages/account/personaldetails.jscomponents/account/personaldetails.jscomponents/search/searchresults.jslib/myportal/loadMyPortalAppealPage.jscomponents/case/representation/representationComplete.js
- reuse of already reviewed route/service evidence from Slices A–C for linked API ownership and building-block classification
Not performed:
- no full dependency inventory
- no repo-wide automated analysis
- no Python
- no runtime code changes
- no lint/tests, because this remains documentation-only assessment work
Recommendation
Next bounded assessment step only:
Slice E — API Maintainer Decision Guide Sample
Focus on a small sample of common maintenance intents, such as:
- adding a new CRM read route
- extending a watched-case style mutation
- adding a document-related route
- extending a finalisation-side orchestration path
Goal:
- document which current patterns a maintainer would most likely copy or reuse
- identify which existing patterns appear preferred vs legacy-for-compatibility
- remain assessment-only
Slice E — Wider API Surface Pattern Validation
Required context read
The following files were re-read before Slice E:
context/portal-api-platform-assessment.mdcontext/architecture.mdcontext/integration-map.mdmemory-bank/change-log.md
Findings
The wider validation pass supports the earlier assessment model.
The API surface is large in file count, but the underlying vocabulary still appears relatively small:
- large route surface
- small contract vocabulary
- small implementation-style vocabulary
- main maintenance issue remains findability and ownership
The folder scan and outlier checks did not reveal a major additional platform family that would overturn Slices A–D.
Instead, the wider surface mostly reinforces that:
pages/api/endpointcontains the majority of CRM-facing route variantspages/api/fileis the main secondary mixed folder where storage plus orchestration concerns accumulate- most routes still fit the previously identified contract shapes and implementation styles
- the main uncertainty is not “unknown route technology” but “where a maintainer should look first”
Folder-Level Validation
Approximate file counts from the bounded listing/count pass:
pages/api/endpoint-> 74 filespages/api/file-> 26 filespages/api/email-> 6 filespages/api/documents-> 1 filepages/api/auth-> 2 filespages/api/admin-> 5 filespages/api/middleware-> 4 files- top-level
pages/apifiles -> 4
pages/api/endpoint
- Approximate size: very large
- Apparent responsibility: CRM relay-facing portal/business-data API catch-all
- Do Slice A–D findings still appear representative? yes
- Unexpected route families? no major new family found
Validation note:
- route names continue to cluster around search/read, myportal reads, document metadata, account/profile, create/update/delete, lookup/config, and proxy variants
pages/api/file
- Approximate size: medium-large
- Apparent responsibility: storage/blob routes plus draft/finalisation and some CRM-adjacent orchestration
- Do Slice A–D findings still appear representative? yes
- Unexpected route families? no major new family, but PDF-generation and involvement routes reinforce the mixed/orchestration character
Validation note:
- outlier review (
createcaseinvolvement_api.js,generateappealpdf.js) still fits the same mixed file/storage/orchestration pattern already documented
pages/api/email
- Approximate size: small
- Apparent responsibility: Notify send plus document/event/list aggregation for email workflows
- Do Slice A–D findings still appear representative? yes
- Unexpected route families? no
Validation note:
getdocuments.jsreinforces that email routes often combine CRM read + document-link generation + downstream notification support rather than introducing a new route family
pages/api/documents
- Approximate size: very small
- Apparent responsibility: direct document download proxy
- Do Slice A–D findings still appear representative? yes
- Unexpected route families? no
pages/api/auth
- Approximate size: very small
- Apparent responsibility: auth/session and locale support
- Do Slice A–D findings still appear representative? yes
- Unexpected route families? no
pages/api/admin
- Approximate size: small
- Apparent responsibility: internal/admin reporting and grouped CRM read views
- Do Slice A–D findings still appear representative? yes
- Unexpected route families? no
Validation note:
getStatusCountsByAppealAndLPA_api.jsstrengthens the view that admin routes are mostly grouped reporting/read transforms over CRM relay data
pages/api/middleware
- Approximate size: very small
- Apparent responsibility: shared API support and relay/runtime helper logic
- Do Slice A–D findings still appear representative? yes
- Unexpected route families? no
Top-level API routes
- Approximate size: very small
- Apparent responsibility: health/meta/static support
- Do Slice A–D findings still appear representative? yes
- Unexpected route families? no
Route Family Validation
Previously identified route families still appear to cover the wider surface:
- search/read
- myportal reads
- account/profile
- create/update/delete
- document retrieval
- storage/blob
- queue/finalisation
- notifications
- admin/reporting
- auth/session
- lookup/config/support
Additional observations from wider route-name validation:
- static/local support data routes such as
getmandatoryfields_api,getpicklists_api, andgetappealtypesfornewappeal_apiare better treated as part of the already-documented lookup/config/support family rather than a genuinely new family - CRM task/contact routes such as
createcrmtask_api.jsfit the existing CRM create/write family - involvement routes under
file/fit the existing orchestration-owned CRM-related mutation pattern already noted in earlier slices - PDF-generation routes under
file/fit the existing storage/document generation orchestration pattern rather than requiring a wholly separate top-level family
Assessment:
- no genuinely new major route family identified
Contract Shape Validation
The previously identified contract shapes still appear sufficient for most of the wider surface:
- Public CRM read
- User-owned CRM read
- CRM create
- CRM update/patch
- CRM delete
- Proxy/pass-through
- Lookup/config/support
- Hybrid upsert/orchestration
Additional validation insight:
- local/static JSON/data support routes (
getmandatoryfields_api,getpicklists_api) fit comfortably within lookup/config/support - admin grouped-reporting routes fit as CRM read + transform rather than a separate contract family
- file-side involvement and PDF routes fit as orchestration or support variants rather than forcing a new contract class
Assessment:
- these contract shapes appear to cover most routes
- no additional mandatory contract shape is currently required for the architecture model
Implementation Style Validation
The implementation-style model also still holds:
1. Helper-oriented relay routes
Still strongly present, especially in endpoint/ and modern admin/reporting reads.
Indicators:
relayGet(...)relayGetData(...)respondError(...)/respondSuccess(...)- relay policy presets
2. Direct-wrapper routes
Still strongly present, especially for CRM create/update/delete and some file-side CRM mutations.
Indicators:
getToken()- route-local
queryUrl WEBAPI_URL + queryUrl + hashAPIPath(queryUrl)- direct
axios(config)
3. Orchestration routes
Still clearly present in:
file/completion/finalisation- PDF generation
- involvement creation
- email-side aggregation routes
Additional major implementation style found?
- No
Closest extra pattern:
- local/static support routes using in-repo JSON/data reads
But this is better treated as a small support variant, not a fourth major implementation style.
Folder Drift Validation
pages/api/documents
- Drift: low
- Reason: narrow folder name still matches actual responsibility closely
pages/api/auth
- Drift: low to moderate
- Reason: still mostly coherent, though CRM locale and Notify behavior cross the folder boundary conceptually
pages/api/admin
- Drift: low
- Reason: sampled routes still align with internal/admin reporting responsibility
pages/api/middleware
- Drift: low
- Reason: folder remains clearly reuse/support oriented
Top-level API routes
- Drift: low
- Reason: health/meta/static support usage remains straightforward
pages/api/email
- Drift: moderate
- Reason: naming suggests email-only behavior, but actual routes can perform CRM/document/event aggregation before notification send
pages/api/file
- Drift: high
- Reason: storage/blob naming no longer fully describes draft orchestration, finalisation, involvement creation, PDF generation, and CRM-adjacent journey behavior housed there
pages/api/endpoint
- Drift: high
- Reason: folder behaves as the historical general-purpose CRM relay catch-all rather than a clearly bounded current responsibility area
Maintenance Hotspots
pages/api/endpoint
- Hotspot level: high
Reason:
- highest route count
- mixed business responsibilities
- helper-oriented and direct-wrapper styles coexist
- many contract-critical routes
- ownership ambiguity highest here
pages/api/file
- Hotspot level: high
Reason:
- second-largest route area
- storage + orchestration + finalisation mixed together
- touches high-risk flows and multiple integrations
pages/api/email
- Hotspot level: medium
Reason:
- smaller route count, but orchestration overlap can surprise maintainers
pages/api/admin
- Hotspot level: medium-low
Reason:
- coherent but still CRM-transform heavy
pages/api/auth
- Hotspot level: medium-high
Reason:
- low file count, but highly sensitive behavior and cross-cutting auth/session implications
pages/api/documents
- Hotspot level: low
Reason:
- very small, narrow responsibility
pages/api/middleware
- Hotspot level: medium-high
Reason:
- tiny surface, but shared helper impact is wide and mistakes would propagate broadly
Confidence Assessment
Representativeness of Slices A–D
- Confidence: high confidence
Why:
- folder-size validation shows the biggest unknown risk area was
endpoint/, and that area has already been sampled repeatedly across earlier slices file/outlier checks still fit the previously identified mixed storage/orchestration model- smaller folders (
email,documents,auth,admin,middleware) did not reveal materially new route families or implementation styles - the outlier review found support variants and special cases, but not a new dominant architectural pattern
Residual caution:
- confidence is high at the platform pattern level, not at the full-route behavioral nuance level
Risks / Cautions
- This remains a pattern-validation pass, not a full inventory
- there may still be route-local nuances not captured here
- High confidence does not mean all individual routes are equivalent
- some outlier handlers still have special transforms, signing rules, or side effects
- Folder-level conclusions should not be mistaken for migration recommendations
- this slice validates representativeness, not reorganisation scope
- The biggest remaining maintenance risk is still ownership ambiguity
- especially in
endpoint/andfile/
- especially in
Validation performed
Manual inspection and bounded searches only.
Performed:
- re-read required Slice E context files
- bounded folder-size count pass across top-level API folders
- targeted route-name searches inside
endpoint,file, andpages/apito validate naming families and implementation indicators - direct representative inspection of selected outlier-style routes, including:
pages/api/endpoint/getmandatoryfields_api.jspages/api/endpoint/createcrmtask_api.jspages/api/file/createcaseinvolvement_api.jspages/api/file/generateappealpdf.jspages/api/email/getdocuments.jspages/api/admin/getStatusCountsByAppealAndLPA_api.js
- reuse of conclusions and evidence from Slices A–D for comparison
Not performed:
- no full route inventory
- no repo-wide automated analysis
- no Python
- no scripts
- no runtime code changes
- no lint/tests, because this remains documentation-only assessment work
Architectural Conclusion
The existing API platform model is now considered representative of the wider API surface at the pattern level.
Current architectural conclusion:
- the wider API surface does not appear to require a materially different platform model from Slices A–D
- the earlier findings generalise well:
endpoint/is the dominant historical CRM relay catch-allfile/is the main secondary mixed storage/orchestration area- route families largely collapse into a limited contract vocabulary
- implementation styles largely collapse into helper-oriented, direct-wrapper, and orchestration styles
- the primary maintainability issue remains findability and ownership, not discovery of a fundamentally different API architecture
Recommendation
Next bounded assessment step only:
Slice F — API Platform Final Synthesis
Goal:
- consolidate Slices A–E into one concise architecture-level API platform view
- state the stable route family model, contract model, implementation-style model, drift model, and maintainer guidance baseline
- remain assessment-only
Slice F — API Platform Final Synthesis
Programme status
Portal Integration Contract & API Platform Assessment
Status: COMPLETE
Closure is supported by the existing evidence because:
- Slices A–E established a stable route-family model
- the wider validation pass reached high confidence at the platform pattern level
- no materially different API platform family or implementation model emerged during bounded wider-surface validation
Executive Summary
The PEDW API platform is large in route count but smaller in underlying structure than the file count first suggests.
At a platform level it can be understood as:
~120 route files
↓
small route-family vocabulary
↓
small contract-shape vocabulary
↓
small implementation-style vocabulary
The API platform therefore feels large primarily because:
- route files are numerous
- route naming has grown historically
- folder responsibility has drifted unevenly
- feature ownership is not always obvious from folder or file name alone
- older and newer implementation styles coexist
The main maintenance problem is not discovery of a fundamentally different API architecture.
The main maintenance problem is:
- findability
- ownership clarity
- consistency and reuse discipline
Final API Platform Model
Stable architecture-level model:
- the dominant platform family is still CRM relay-backed portal APIs
- the main secondary platform family is storage/blob plus draft/finalisation orchestration
- notification, auth, documents, admin, and middleware form smaller supporting families
- route count overstates structural diversity because many routes are variants of repeated contract shapes
- the platform is mixed but explainable once grouped by route family, contract shape, and implementation style
Route-Family Model
The stable route-family model is:
1. CRM relay routes
- mainly under
pages/api/endpoint - includes search, myportal reads, account/profile reads, lookups, and CRM mutations
2. Storage/blob routes
- mainly under
pages/api/file - includes blob listing, upload, delete, progress, and draft file handling
3. Finalisation/orchestration routes
- concentrated in
pages/api/file, with supporting CRM mutation routes inendpoint - includes draft-to-submission transitions, completion-message flows, PDF generation, and related side effects
4. Email/notification routes
- mainly under
pages/api/email - includes thin Notify send routes and broader aggregation/orchestration routes
5. Document download routes
- mainly under
pages/api/documents - narrow published-document download proxy behavior
6. Auth/session routes
- mainly under
pages/api/auth - includes NextAuth/session behavior and locale-aware auth support
7. Admin/internal routes
- mainly under
pages/api/admin - grouped CRM reporting/read transforms for internal/admin use
8. Middleware/helper routes
- under
pages/api/middleware - response helpers, relay forwarding, multipart support, retry/policy helpers
9. Local utility/meta routes
- top-level API utility files and a few support-style routes
- health, docs/static/meta support, and local/config data reads
Contract-Shape Model
The stable contract-shape model is:
CRM-facing shapes
- Public CRM read
- User-owned CRM read
- CRM create
- CRM update/patch
- CRM delete
- Proxy/pass-through
- Lookup/config/support
- Hybrid upsert/orchestration
Storage/finalisation/notification shapes
- Storage read/write/delete
- Queue/finalisation
- Notify send / notification orchestration
Assessment note:
- these shapes are sufficient to explain most of the observed API surface
- many apparent route differences are variants of one of these shapes rather than separate architectural categories
Implementation-Style Model
The stable implementation-style model consists of three main styles.
1. Newer helper-oriented
Typical indicators:
relayGet(...)relayGetData(...)respondSuccess(...)respondError(...)- relay policy presets
Typical fit:
- CRM read routes
- proxy/read routes
- grouped read/transform routes
2. Older direct-wrapper
Typical indicators:
getToken()- direct
axios(config) - manual
WEBAPI_URL + queryUrl + hashAPIPath(queryUrl)
Typical fit:
- CRM create/update/delete wrappers
- some file-side CRM mutation helpers
Assessment note:
- these patterns are not “wrong”; they reflect prior delivery needs and stable historical route construction
- the main maintainability question is whether they should be copied forward into new work when shared helpers now exist
3. Orchestration-heavy
Typical fit:
- finalisation routes
- email aggregation routes
- storage + queue + CRM side-effect routes
- PDF generation and file-adjacent journey transitions
Assessment note:
- these routes are structurally important because they cross integration boundaries and often sit at contract-critical workflow transitions
Folder Drift Model
Folder drift affects maintainability because folder name and actual responsibility do not always align.
Low drift
documentsadminmiddleware- top-level utility/meta
These are relatively easy to find and reason about.
Low / moderate drift
auth
The folder is still coherent, but auth behavior crosses into CRM and Notify concerns.
Moderate drift
email
The folder name suggests email-only work, but some routes perform CRM/document/event aggregation before notification send.
High drift
endpointfile
Why this matters:
endpointbehaves as a historical general-purpose CRM relay catch-allfilenow contains blob/storage behavior, draft support, finalisation, involvement creation, PDF generation, and CRM-adjacent orchestration- this drift increases scan cost and weakens ownership clarity
Maintenance Hotspots
High
pages/api/endpointpages/api/file
Why:
- highest route concentration
- mixed responsibilities
- mixed implementation styles
- many contract-critical routes
- ownership ambiguity is strongest here
Medium-high
pages/api/authpages/api/middleware
Why:
- small surfaces but high leverage and high sensitivity
- mistakes there can have broad downstream effects
Medium
pages/api/email
Why:
- route count is small, but orchestration overlap makes behavior less obvious than the folder name suggests
Lower
pages/api/documentspages/api/admin
Why:
- narrower and more coherent responsibilities
- still important, but less structurally confusing than
endpointandfile
Maintainer Guidance Baseline
For future API work, the stable baseline should be:
- Identify the owning feature or journey first
- do not start from route name alone if the flow is contract-critical
- Identify the integration touched
- CRM relay, Azure Storage, Azure Queue/finalisation, Notify, NextAuth, or local-only support
- Identify contract-criticality before editing
- public search, myportal, file handling, document delivery, auth/session, and finalisation need higher caution
- Prefer existing shared helpers where suitable
- especially for CRM read routes and standardized response handling
- Prefer
respondSuccess(...)/respondError(...)for new JSON responses - Prefer helper-oriented relay reads for new CRM reads where appropriate
- Reuse storage helpers and established hash validation patterns for storage APIs
- Keep Notify routes thin unless orchestration is genuinely required
- Do not blindly copy older direct-wrapper patterns into new work
- Do not refactor stable legacy routes without explicit approval and characterization
What Is Proven / Not Proven
Proven
- Slices A–E are representative at the API platform pattern level
- route count overstates true structural diversity
- the main maintenance issue is findability and ownership
- a small number of repeated contract and implementation patterns explain most routes
Not Proven
- no full route-by-route inventory was produced
- no consolidation safety assessment has been performed
- no implementation readiness has been approved
- no route movement or removal is recommended yet
Recommendation
The Portal Integration Contract & API Platform Assessment should now be considered complete.
Recommended future planning stream only:
- API Route Map / Maintainer Guide
or
- API Rationalisation Planning
But only as a future planning stream.
No implementation work is recommended from this assessment alone.