1+ import { isSegmentSubproject , populateSegmentRelations } from '@crowd/data-access-layer/src/segments'
2+ import { getServiceChildLogger } from '@crowd/logging'
3+
14import SegmentRepository from '../database/repositories/segmentRepository'
25
6+ const log = getServiceChildLogger ( 'segmentMiddleware' )
7+
38export async function segmentMiddleware ( req , res , next ) {
49 try {
510 let segments : any = null
611 const segmentRepository = new SegmentRepository ( req )
712
8- if ( req . params . segmentId ) {
9- // for param requests, segments will be in the url
10- segments = { rows : await segmentRepository . findInIds ( [ req . params . segmentId ] ) }
11- } else if ( req . query . segments ) {
12- // for get requests, segments will be in query
13- segments = { rows : await segmentRepository . findInIds ( req . query . segments ) }
13+ // Note: req.params is NOT available here. This middleware is registered via app.use(),
14+ // which runs before Express matches a specific route and populates req.params.
15+ // Any check on req.params (e.g. req.params.segmentId) would always be undefined.
16+ // Route handlers that need a specific segment by ID (e.g. GET /segment/:segmentId)
17+ // read req.params directly and ignore req.currentSegments entirely — so the
18+ // resolution below is harmless for those endpoints.
19+ if ( req . query . segments ) {
20+ // GET requests
21+ segments = {
22+ rows : await resolveToLeafSegments ( segmentRepository , req . query . segments , req ) ,
23+ }
1424 } else if ( req . body . segments ) {
15- // for post and put requests, segments will be in body
16- segments = { rows : await segmentRepository . findInIds ( req . body . segments ) }
25+ // POST/PUT requests
26+ segments = {
27+ rows : await resolveToLeafSegments ( segmentRepository , req . body . segments , req ) ,
28+ }
1729 } else {
1830 segments = await segmentRepository . querySubprojects ( { limit : 1 , offset : 0 } )
1931 }
@@ -25,3 +37,57 @@ export async function segmentMiddleware(req, res, next) {
2537 next ( error )
2638 }
2739}
40+
41+ /**
42+ * Resolves segment IDs to their leaf sub-projects.
43+ *
44+ * If all provided IDs are already sub-projects (leaf level), returns them as-is
45+ * without any extra DB call — fully backward-compatible with the current behavior.
46+ *
47+ * If any ID is a project or project group (non-leaf), expands it to all its
48+ * active sub-projects and applies populateSegmentRelations to match the shape
49+ * that downstream services expect from req.currentSegments.
50+ */
51+ async function resolveToLeafSegments (
52+ segmentRepository : SegmentRepository ,
53+ segmentIds : string [ ] ,
54+ req : any ,
55+ ) {
56+ const fetched = await segmentRepository . findInIds ( segmentIds )
57+
58+ const nonLeaf = fetched . filter ( ( s ) => ! isSegmentSubproject ( s ) )
59+
60+ const segmentLevel = ( s : any ) =>
61+ s . grandparentSlug ? 'subproject' : s . parentSlug ? 'project' : 'projectGroup'
62+
63+ if ( nonLeaf . length === 0 ) {
64+ // All IDs are already leaf segments — current behavior, no change.
65+ log . debug (
66+ {
67+ api : `${ req . method } ${ req . path } ` ,
68+ usedInDbQueries : fetched . map ( ( s ) => ( { id : s . id , name : s . name , level : segmentLevel ( s ) } ) ) ,
69+ } ,
70+ `All segments are already leaf — used as-is in DB queries` ,
71+ )
72+ return fetched
73+ }
74+
75+ const leafRecords = await segmentRepository . getSegmentSubprojects ( segmentIds )
76+
77+ log . warn (
78+ {
79+ api : `${ req . method } ${ req . path } ` ,
80+ '⚠️ WITHOUT_RESOLUTION_would_have_used' : {
81+ segments : nonLeaf . map ( ( s ) => ( { id : s . id , name : s . name , level : segmentLevel ( s ) } ) ) ,
82+ count : segmentIds . length ,
83+ } ,
84+ '✅ WITH_RESOLUTION_will_use' : {
85+ segments : leafRecords . map ( ( s : any ) => ( { id : s . id , name : ( s as any ) . name } ) ) ,
86+ count : leafRecords . length ,
87+ } ,
88+ } ,
89+ `⚠️ NON-LEAF SEGMENT DETECTED — DB queries will use resolved leaf segments instead of the received ones` ,
90+ )
91+
92+ return leafRecords . map ( populateSegmentRelations )
93+ }
0 commit comments