Files
goodgo-platform/apps/api/src/modules/industrial/presentation/dto/parks-bbox.dto.ts
Ho Ngoc Hai 63a449ad9d
Some checks failed
CI / AI Services (Python) — Smoke (push) Waiting to run
CI / Lint → Typecheck → Test → Build (22) (push) Failing after 6s
CI / E2E Tests (push) Has been skipped
CodeQL Analysis / CodeQL (javascript-typescript) (push) Failing after 1m7s
Deploy / Build API Image (push) Failing after 7s
Deploy / Build Web Image (push) Failing after 4s
Deploy / Build AI Services Image (push) Failing after 7s
E2E Tests / Playwright E2E (push) Failing after 15s
Security Scanning / Dependency Audit (pnpm) (push) Failing after 3s
Security Scanning / Trivy Scan — API Image (push) Failing after 44s
Security Scanning / Trivy Scan — Web Image (push) Failing after 44s
Security Scanning / Trivy Scan — AI Services Image (push) Failing after 46s
Security Scanning / Trivy Filesystem Scan (push) Failing after 45s
Deploy / Deploy to Staging (push) Has been skipped
Deploy / Smoke Test Staging (push) Has been skipped
Deploy / Deploy to Production (push) Has been skipped
Deploy / Smoke Test Production (push) Has been skipped
Security Scanning / Security Gate (push) Failing after 1s
Deploy / Rollback Staging (push) Has been skipped
Deploy / Rollback Production (push) Has been skipped
feat(industrial): bulk-promote OSM imports + drop demo seed
The KCN catalog was running in two parallel modes — 20 hand-curated demo
rows (MANUAL) plus 2,193 OSM imports stuck in the review queue. The user
asked to drop the demo data and publish all OSM rows in one shot, so the
public catalog reflects the full Vietnamese landscape from the start.

Steps run against the dev DB:
  • DELETE 20 MANUAL parks (12 IndustrialListing rows cascaded out)
  • UPDATE 2,193 OSM rows → dataSource = 'OSM_PROMOTED', isPublic = true
  • DELETE 490 polygons that bled across the northern border bbox and
    have only CJK names (no Latin / Vietnamese letter at all). These
    were Chinese industrial sites — Fangcheng Port, Guangxi Steel,
    BYD test site etc. — picked up because the Quảng Ninh / Lạng Sơn
    chunks of the Overpass query include the cross-border buffer.

Artefacts:
  • `scripts/promote-all-osm.ts` — re-runnable bulk action with --dry-run
    and --keep-manual flags. Idempotent (already-promoted rows skipped).
  • `scripts/sync-osm-industrial-parks.ts` now drops non-Latin names at
    `parseFeature()` so the next monthly sync won't re-import them.

Catalog ergonomics improvements that followed:
  • PrismaIndustrialParkRepository.list now `ORDER BY totalAreaHa DESC
    NULLS LAST` so the largest KCN appear first instead of being buried
    under 0-ha NODE imports. Bàu Bàng (2,597 ha), Nhơn Trạch (2,535 ha),
    Phước Đông, Hòa Lạc, etc. now lead the list.
  • IndustrialParksBboxDto default `limit` raised 1000 → 3000 so a
    country-zoom request returns the entire promoted set without
    truncation. The bbox handler already orders by area DESC so the
    truncated case keeps the meaningful entries.

Final catalog: 1,703 promoted KCN, 0 raw OSM, 0 manual.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-30 00:19:03 +07:00

69 lines
1.8 KiB
TypeScript

import { ApiProperty } from '@nestjs/swagger';
import { Transform, Type } from 'class-transformer';
import { IsBoolean, IsInt, IsNumber, Max, Min } from 'class-validator';
/**
* Query params for `GET /industrial/parks/by-bbox`.
*
* The bbox covers the user's current Mapbox viewport. `zoom` controls
* whether the response includes polygon boundaries (zoom >= 12) or just
* Point centroids.
*/
export class IndustrialParksBboxDto {
@ApiProperty({ example: 8.0, description: 'Southern (min) latitude of the viewport' })
@Type(() => Number)
@IsNumber()
@Min(-90)
@Max(90)
south!: number;
@ApiProperty({ example: 102.0, description: 'Western (min) longitude of the viewport' })
@Type(() => Number)
@IsNumber()
@Min(-180)
@Max(180)
west!: number;
@ApiProperty({ example: 23.5, description: 'Northern (max) latitude of the viewport' })
@Type(() => Number)
@IsNumber()
@Min(-90)
@Max(90)
north!: number;
@ApiProperty({ example: 110.0, description: 'Eastern (max) longitude of the viewport' })
@Type(() => Number)
@IsNumber()
@Min(-180)
@Max(180)
east!: number;
@ApiProperty({ example: 8, description: 'Mapbox zoom level (0-22)' })
@Type(() => Number)
@IsInt()
@Min(0)
@Max(22)
zoom!: number;
@ApiProperty({
required: false,
default: false,
description: 'Include raw OSM imports (admin only). Default: false.',
})
@Transform(({ value }) => value === 'true' || value === true)
@IsBoolean()
includeOsmRaw?: boolean = false;
@ApiProperty({
required: false,
default: 3000,
description:
'Max features to return. Default 3000 covers the entire promoted KCN catalog at country zoom; raise to 5000 if you also include raw OSM imports.',
})
@Type(() => Number)
@IsInt()
@Min(1)
@Max(5000)
limit?: number = 3000;
}