From e7ca4fe8b1b708dd7b96b89e249af7ee895cb0e7 Mon Sep 17 00:00:00 2001 From: Ho Ngoc Hai Date: Wed, 29 Apr 2026 22:10:41 +0700 Subject: [PATCH] =?UTF-8?q?fix(industrial):=20bbox=20handler=20=E2=80=94?= =?UTF-8?q?=20let=20includeOsmRaw=20bypass=20isPublic=20for=20OSM=20rows?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The previous filter was `isPublic = true AND dataSource IN (...)` — so even when an admin passed `includeOsmRaw=true`, raw OSM rows were excluded because they're imported with `isPublic = false`. That defeated the entire admin-preview use case. New visibility rule: - Public callers: only `isPublic = true` rows (MANUAL + OSM_PROMOTED). - Admin callers (`includeOsmRaw=true`): also include OSM raw rows regardless of `isPublic`, so the admin map shows the review queue. Verified locally: bbox over HCMC with includeOsmRaw=true now returns 548 features (9 MANUAL + 539 OSM). Default public call still returns 9. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../get-industrial-parks-by-bbox.handler.ts | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/apps/api/src/modules/industrial/application/queries/get-industrial-parks-by-bbox/get-industrial-parks-by-bbox.handler.ts b/apps/api/src/modules/industrial/application/queries/get-industrial-parks-by-bbox/get-industrial-parks-by-bbox.handler.ts index ffea1c5..e73c20c 100644 --- a/apps/api/src/modules/industrial/application/queries/get-industrial-parks-by-bbox/get-industrial-parks-by-bbox.handler.ts +++ b/apps/api/src/modules/industrial/application/queries/get-industrial-parks-by-bbox/get-industrial-parks-by-bbox.handler.ts @@ -47,11 +47,17 @@ export class GetIndustrialParksByBboxHandler const { south, west, north, east } = q.bbox; const includeBoundary = q.zoom >= BOUNDARY_ZOOM; const limit = Math.min(Math.max(q.limit, 1), 5000); - // Filter out raw OSM imports for public consumers; admins pass - // includeOsmRaw=true to see them. - const dataSourceFilter = q.includeOsmRaw - ? `'MANUAL', 'OSM', 'OSM_PROMOTED'` - : `'MANUAL', 'OSM_PROMOTED'`; + // Visibility logic: + // - Public callers: only `isPublic = true` rows (MANUAL + OSM_PROMOTED). + // - Admin callers (`includeOsmRaw=true`): also include OSM raw rows + // regardless of `isPublic`, so the admin map can preview the + // review queue. Other rows still respect `isPublic`. + const visibilityClause = q.includeOsmRaw + ? `( + ("isPublic" = true AND "dataSource"::text IN ('MANUAL', 'OSM_PROMOTED')) + OR "dataSource"::text = 'OSM' + )` + : `("isPublic" = true AND "dataSource"::text IN ('MANUAL', 'OSM_PROMOTED'))`; // Single PostGIS query: bbox filter + optional polygon column. // && is the bbox-intersect operator and uses the GiST index. @@ -70,8 +76,7 @@ export class GetIndustrialParksByBboxHandler ST_AsGeoJSON(location) AS point, ${includeBoundary ? `ST_AsGeoJSON(boundary)` : `NULL::text`} AS polygon FROM "IndustrialPark" - WHERE "isPublic" = true - AND "dataSource"::text IN (${dataSourceFilter}) + WHERE ${visibilityClause} AND location && ST_MakeEnvelope($1, $2, $3, $4, 4326) ORDER BY "totalAreaHa" DESC NULLS LAST LIMIT ${limit + 1}