Merged PR 2428: Add documents API grouping facade slice
Add documents API grouping facade slice Related work items: #23754
This commit is contained in:
@@ -201,7 +201,7 @@ export const getBasicSearchDetailsPaged = async (
|
||||
|
||||
export const getSearchDocumentDetails = (incidentID) => {
|
||||
return getJson(
|
||||
"/api/endpoint/getsearchdocumentdetails_api?incidentid=" + incidentID
|
||||
"/api/documents/get-search-document-details?incidentid=" + incidentID
|
||||
).catch((error) => {
|
||||
consoleLogger(error);
|
||||
throw error;
|
||||
@@ -210,7 +210,7 @@ export const getSearchDocumentDetails = (incidentID) => {
|
||||
|
||||
export const getSearchDocumentTypes = (incidentID) => {
|
||||
return getJson(
|
||||
"/api/endpoint/getsearchdocumentTypes_api?incidentid=" + incidentID
|
||||
"/api/documents/get-search-document-types?incidentid=" + incidentID
|
||||
).catch((error) => {
|
||||
consoleLogger(error);
|
||||
});
|
||||
@@ -225,7 +225,7 @@ export const getSearchDocumentDetailsPaged = (
|
||||
documentType
|
||||
) => {
|
||||
return getJson(
|
||||
"/api/endpoint/getsearchdocumentdetailspaged_api?incidentid=" +
|
||||
"/api/documents/get-search-document-details-paged?incidentid=" +
|
||||
incidentID +
|
||||
"&pageNumber=" +
|
||||
pageNumber +
|
||||
|
||||
@@ -9,6 +9,10 @@ Pilot status update (2026-06-25):
|
||||
- first additive grouping façade pilot implemented for watched-case APIs under `pages/api/subscriptions/`
|
||||
- first internal consumer (`actions/services/portalDirectService.js` watched-case methods) now targets the grouped façade routes
|
||||
- the active watched-case vertical slice now includes grouped adoption for both normal watched-case reads and proxy watched-case reads used by the current UI journey
|
||||
- second additive grouping façade vertical slice implemented for the active published-documents metadata journey under `pages/api/documents/`
|
||||
- active published-document metadata consumer (`actions/services/searchDirectService.js`) now targets grouped documents façade routes for details, paged details, and document-type reads
|
||||
- published document download remains on the existing grouped runtime path `pages/api/documents/download/[id].js`
|
||||
- legacy document metadata endpoint routes remain canonical and stable behind the additive façade wrappers
|
||||
- legacy watched-case endpoint routes remain canonical and stable
|
||||
- no old route removal or migration has occurred
|
||||
- runtime behaviour is intended to remain unchanged because the grouped routes delegate to the existing handlers
|
||||
@@ -189,6 +193,31 @@ It means:
|
||||
- runtime behaviour remains unchanged through delegation
|
||||
- `deletewatchedcasesproxy_api` remains a legacy/support route outside the grouped pilot scope because it is not part of the currently adopted normal watched-case service path.
|
||||
|
||||
#### Additional vertical-slice proof point — published documents
|
||||
|
||||
- The active published-documents journey now has a second complete additive grouping slice for metadata discovery only:
|
||||
- grouped façade routes exist for the active metadata/type reads under `pages/api/documents/`
|
||||
- `actions/services/searchDirectService.js` targets those grouped routes for:
|
||||
- `getSearchDocumentDetails`
|
||||
- `getSearchDocumentDetailsPaged`
|
||||
- `getSearchDocumentTypes`
|
||||
- legacy endpoint handlers remain present and canonical behind the façade:
|
||||
- `pages/api/endpoint/getsearchdocumentdetails_api.js`
|
||||
- `pages/api/endpoint/getsearchdocumentdetailspaged_api.js`
|
||||
- `pages/api/endpoint/getsearchdocumentTypes_api.js`
|
||||
- runtime behaviour remains unchanged through direct delegation and unchanged service-layer query contracts
|
||||
- The active bounded audit also established that:
|
||||
- the current UI document journey is routed through `components/case/documents.js`
|
||||
- the current common metadata service layer is `actions/services/searchDirectService.js`
|
||||
- the existing grouped route `pages/api/documents/download/[id].js` remains the runtime download path and was intentionally left unchanged
|
||||
- `getsearchdocumenthistory_api.js` and `getsearchdocumenthistorypaged_api.js` remain present as legacy/support routes outside the active grouped adoption scope because they were not surfaced in the currently active UI journey
|
||||
- For this documents slice, a complete vertical grouping slice means:
|
||||
- active document metadata/type journey calls have grouped façade routes
|
||||
- the active common service layer uses those grouped routes
|
||||
- legacy handlers remain present and canonical
|
||||
- download behaviour remains unchanged
|
||||
- no route migration, deletion, or contract change has occurred
|
||||
|
||||
---
|
||||
|
||||
### Stage 3 — Documentation Maturity
|
||||
|
||||
@@ -18,6 +18,78 @@ Follow-ups:
|
||||
|
||||
---
|
||||
|
||||
### CL-2026-06-25-API-GROUPING-FACADE-DOCUMENTS-VERTICAL-SLICE: active published-document metadata grouping and service adoption
|
||||
|
||||
date: 2026-06-25
|
||||
author: Cline
|
||||
scope: `pages/api/documents/get-search-document-details.js`, `pages/api/documents/get-search-document-details-paged.js`, `pages/api/documents/get-search-document-types.js`, `actions/services/searchDirectService.js`, `tests/phase22/api-grouping-facade-documents.test.cjs`, `context/api-grouping-adoption-roadmap.md`
|
||||
type: change
|
||||
rationale: Implement the second additive API grouping façade vertical slice by grouping the active published-document metadata journey under `pages/api/documents/` and adopting the grouped routes only in the existing common document metadata service layer, while preserving the existing download route and legacy endpoint handlers unchanged.
|
||||
impact: Runtime behaviour is intended to remain unchanged; grouped document façade routes now cover the active metadata/type journey calls, `actions/services/searchDirectService.js` now targets those grouped routes, legacy endpoint handlers remain canonical, the existing grouped download route remains unchanged, and no migration, route deletion, auth change, CRM query change, hash-link generation change, payload change, or response-contract change has occurred.
|
||||
status: completed
|
||||
|
||||
Summary:
|
||||
|
||||
- Confirmed the required context was read before implementation:
|
||||
- `context/api-grouping-plan.md`
|
||||
- `context/api-grouping-adoption-roadmap.md`
|
||||
- `context/journey-architecture-map.md`
|
||||
- `context/api-route-map.md`
|
||||
- `context/architecture.md`
|
||||
- `memory-bank/change-log.md`
|
||||
- Performed a bounded audit of the active published-documents journey across services, API handlers, and frontend components.
|
||||
- Audit findings established that:
|
||||
- active document metadata retrieval is surfaced through `components/case/documents.js`
|
||||
- active document metadata/type calls already route through the common service layer `actions/services/searchDirectService.js`
|
||||
- published-document downloads already use the grouped runtime route `pages/api/documents/download/[id].js`
|
||||
- legacy metadata handlers generate `pinswg_hashlink` values that continue to point at the unchanged grouped download route
|
||||
- `getsearchdocumenthistory_api.js` and `getsearchdocumenthistorypaged_api.js` remain present but were not surfaced in the currently active UI journey and therefore remained outside grouped adoption scope
|
||||
- Added grouped façade routes under `pages/api/documents/` for the active metadata journey only:
|
||||
- `get-search-document-details.js`
|
||||
- `get-search-document-details-paged.js`
|
||||
- `get-search-document-types.js`
|
||||
- Implemented each façade as the smallest safe compatibility wrapper:
|
||||
- import the existing legacy endpoint handler
|
||||
- delegate `req` and `res` directly to that existing handler
|
||||
- Updated only the suitable common service layer in `actions/services/searchDirectService.js` to target grouped façade routes for:
|
||||
- `getSearchDocumentDetails`
|
||||
- `getSearchDocumentDetailsPaged`
|
||||
- `getSearchDocumentTypes`
|
||||
- Left the following unchanged:
|
||||
- CRM queries
|
||||
- download behaviour
|
||||
- hash-link generation
|
||||
- authentication
|
||||
- response contracts
|
||||
- payloads
|
||||
- file locations of legacy handlers
|
||||
- Added focused characterization coverage to prove:
|
||||
- grouped document façade routes delegate correctly
|
||||
- active document service methods now target grouped document routes
|
||||
- legacy document endpoint handlers remain present
|
||||
- active service-layer query-contract cues remain unchanged
|
||||
- the runtime download path remains `/api/documents/download/[id]`
|
||||
- Updated the adoption roadmap to record the active documents grouping slice and its bounded scope.
|
||||
|
||||
Validation:
|
||||
|
||||
- Focused validation only intended for this slice:
|
||||
- `npx eslint actions/services/searchDirectService.js pages/api/documents/get-search-document-details.js pages/api/documents/get-search-document-details-paged.js pages/api/documents/get-search-document-types.js tests/phase22/api-grouping-facade-documents.test.cjs context/api-grouping-adoption-roadmap.md memory-bank/change-log.md`
|
||||
- `node tests/phase22/api-grouping-facade-documents.test.cjs`
|
||||
- No repository-wide validation run.
|
||||
|
||||
Follow-ups:
|
||||
|
||||
- The active Documents journey is now a complete vertical grouping slice for the bounded published-document metadata/type path:
|
||||
- grouped façade routes
|
||||
- active service-layer adoption
|
||||
- legacy canonical handlers retained
|
||||
- unchanged grouped download path
|
||||
- unchanged behaviour
|
||||
- Any future expansion beyond this bounded scope should be a separate slice, for example if history/support routes are later proven to be part of an actively adopted user journey.
|
||||
|
||||
---
|
||||
|
||||
### CL-2026-06-25-API-GROUPING-FACADE-SUBSCRIPTIONS-VERTICAL-SLICE-COMPLETION: watched-case proxy read adoption and scope closure
|
||||
|
||||
date: 2026-06-25
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
import legacyGetSearchDocumentDetailsPagedHandler from "../endpoint/getsearchdocumentdetailspaged_api";
|
||||
|
||||
export default async function getSearchDocumentDetailsPagedFacade(req, res) {
|
||||
return legacyGetSearchDocumentDetailsPagedHandler(req, res);
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
import legacyGetSearchDocumentDetailsHandler from "../endpoint/getsearchdocumentdetails_api";
|
||||
|
||||
export default async function getSearchDocumentDetailsFacade(req, res) {
|
||||
return legacyGetSearchDocumentDetailsHandler(req, res);
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
import legacyGetSearchDocumentTypesHandler from "../endpoint/getsearchdocumentTypes_api";
|
||||
|
||||
export default async function getSearchDocumentTypesFacade(req, res) {
|
||||
return legacyGetSearchDocumentTypesHandler(req, res);
|
||||
}
|
||||
@@ -0,0 +1,189 @@
|
||||
const assert = require("assert");
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
|
||||
const { loadModule, createRes } = require("../phase21/_shared.cjs");
|
||||
|
||||
const rootDir = path.resolve(__dirname, "..", "..");
|
||||
|
||||
const tests = [];
|
||||
const test = (name, fn) => tests.push({ name, fn });
|
||||
|
||||
const read = (relativePath) =>
|
||||
fs.readFileSync(path.join(rootDir, relativePath), "utf8");
|
||||
|
||||
test("documents get-search-document-details facade delegates to legacy handler", async () => {
|
||||
const calls = [];
|
||||
const mod = loadModule(
|
||||
"pages/api/documents/get-search-document-details.js",
|
||||
{
|
||||
legacyGetSearchDocumentDetailsHandler: async (req, res) => {
|
||||
calls.push({ req, res });
|
||||
return res.status(200).json({ ok: true, route: "details" });
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
const req = { method: "GET", query: { incidentid: "inc-1" } };
|
||||
const res = createRes();
|
||||
await mod.default(req, res);
|
||||
|
||||
assert.strictEqual(calls.length, 1);
|
||||
assert.strictEqual(calls[0].req, req);
|
||||
assert.strictEqual(calls[0].res, res);
|
||||
assert.strictEqual(res.state.statusCode, 200);
|
||||
assert.deepStrictEqual(JSON.parse(JSON.stringify(res.state.jsonBody)), {
|
||||
ok: true,
|
||||
route: "details"
|
||||
});
|
||||
});
|
||||
|
||||
test("documents get-search-document-details-paged facade delegates to legacy handler", async () => {
|
||||
const calls = [];
|
||||
const mod = loadModule(
|
||||
"pages/api/documents/get-search-document-details-paged.js",
|
||||
{
|
||||
legacyGetSearchDocumentDetailsPagedHandler: async (req, res) => {
|
||||
calls.push({ req, res });
|
||||
return res
|
||||
.status(200)
|
||||
.json({ ok: true, route: "details-paged" });
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
const req = {
|
||||
method: "GET",
|
||||
query: {
|
||||
incidentid: "inc-2",
|
||||
pageNumber: "1",
|
||||
orderby: "createdon",
|
||||
fieldSort: "asc",
|
||||
showNumberOfRecords: "10",
|
||||
documentType: "all"
|
||||
}
|
||||
};
|
||||
const res = createRes();
|
||||
await mod.default(req, res);
|
||||
|
||||
assert.strictEqual(calls.length, 1);
|
||||
assert.strictEqual(calls[0].req, req);
|
||||
assert.strictEqual(calls[0].res, res);
|
||||
assert.strictEqual(res.state.statusCode, 200);
|
||||
assert.deepStrictEqual(JSON.parse(JSON.stringify(res.state.jsonBody)), {
|
||||
ok: true,
|
||||
route: "details-paged"
|
||||
});
|
||||
});
|
||||
|
||||
test("documents get-search-document-types facade delegates to legacy handler", async () => {
|
||||
const calls = [];
|
||||
const mod = loadModule("pages/api/documents/get-search-document-types.js", {
|
||||
legacyGetSearchDocumentTypesHandler: async (req, res) => {
|
||||
calls.push({ req, res });
|
||||
return res
|
||||
.status(200)
|
||||
.json([{ pinswg_isharedocumentlocations: 1, count: 2 }]);
|
||||
}
|
||||
});
|
||||
|
||||
const req = { method: "GET", query: { incidentid: "inc-3" } };
|
||||
const res = createRes();
|
||||
await mod.default(req, res);
|
||||
|
||||
assert.strictEqual(calls.length, 1);
|
||||
assert.strictEqual(calls[0].req, req);
|
||||
assert.strictEqual(calls[0].res, res);
|
||||
assert.strictEqual(res.state.statusCode, 200);
|
||||
assert.deepStrictEqual(JSON.parse(JSON.stringify(res.state.jsonBody)), [
|
||||
{ pinswg_isharedocumentlocations: 1, count: 2 }
|
||||
]);
|
||||
});
|
||||
|
||||
test("legacy document metadata endpoint files remain present", async () => {
|
||||
const legacyFiles = [
|
||||
"pages/api/endpoint/getsearchdocumentdetails_api.js",
|
||||
"pages/api/endpoint/getsearchdocumentdetailspaged_api.js",
|
||||
"pages/api/endpoint/getsearchdocumentTypes_api.js",
|
||||
"pages/api/endpoint/getsearchdocumenthistory_api.js",
|
||||
"pages/api/endpoint/getsearchdocumenthistorypaged_api.js",
|
||||
"pages/api/documents/download/[id].js"
|
||||
];
|
||||
|
||||
legacyFiles.forEach((filePath) => {
|
||||
assert.strictEqual(
|
||||
fs.existsSync(path.join(rootDir, filePath)),
|
||||
true,
|
||||
filePath
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
test("searchDirectService document journey methods now target grouped documents facade routes", async () => {
|
||||
const source = read("actions/services/searchDirectService.js");
|
||||
|
||||
assert.match(source, /\/api\/documents\/get-search-document-details\?/);
|
||||
assert.match(
|
||||
source,
|
||||
/\/api\/documents\/get-search-document-details-paged\?/
|
||||
);
|
||||
assert.match(source, /\/api\/documents\/get-search-document-types\?/);
|
||||
});
|
||||
|
||||
test("searchDirectService no longer targets legacy document metadata routes for adopted methods", async () => {
|
||||
const source = read("actions/services/searchDirectService.js");
|
||||
|
||||
assert.doesNotMatch(
|
||||
source,
|
||||
/\/api\/endpoint\/getsearchdocumentdetails_api/
|
||||
);
|
||||
assert.doesNotMatch(
|
||||
source,
|
||||
/\/api\/endpoint\/getsearchdocumentdetailspaged_api/
|
||||
);
|
||||
assert.doesNotMatch(source, /\/api\/endpoint\/getsearchdocumentTypes_api/);
|
||||
});
|
||||
|
||||
test("document runtime contract cues remain unchanged in searchDirectService", async () => {
|
||||
const source = read("actions/services/searchDirectService.js");
|
||||
|
||||
assert.match(source, /incidentid=/);
|
||||
assert.match(source, /pageNumber=/);
|
||||
assert.match(source, /orderby=/);
|
||||
assert.match(source, /fieldSort=/);
|
||||
assert.match(source, /showNumberOfRecords=/);
|
||||
assert.match(source, /documentType=/);
|
||||
});
|
||||
|
||||
test("document download route remains the runtime download path", async () => {
|
||||
const metadataDetailsSource = read(
|
||||
"pages/api/endpoint/getsearchdocumentdetails_api.js"
|
||||
);
|
||||
const metadataPagedSource = read(
|
||||
"pages/api/endpoint/getsearchdocumentdetailspaged_api.js"
|
||||
);
|
||||
|
||||
assert.match(metadataDetailsSource, /\/api\/documents\/download\//);
|
||||
assert.match(metadataPagedSource, /\/api\/documents\/download\//);
|
||||
});
|
||||
|
||||
async function run() {
|
||||
let failures = 0;
|
||||
|
||||
for (const { name, fn } of tests) {
|
||||
try {
|
||||
await fn();
|
||||
console.log(`✓ ${name}`);
|
||||
} catch (error) {
|
||||
failures += 1;
|
||||
console.error(`✗ ${name}`);
|
||||
console.error(error);
|
||||
}
|
||||
}
|
||||
|
||||
if (failures > 0) {
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
run();
|
||||
Reference in New Issue
Block a user