feat(seed): add MacroeconomicData and InfrastructureProject seed data

Add seed-macro-infra.ts with 144 macroeconomic data points (HCMC + Hanoi,
6 indicators, quarterly 2023-2025) and 15 infrastructure projects with
PostGIS coordinates (Metro Line 1, Thu Duc Innovation District, Ring Road 3,
Long Thanh Airport, Can Gio Bridge, etc.). Integrated into main seed pipeline.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
Ho Ngoc Hai
2026-04-16 14:18:41 +07:00
parent 57db3fe388
commit b22543d59e
2 changed files with 415 additions and 2 deletions

401
scripts/seed-macro-infra.ts Normal file
View File

@@ -0,0 +1,401 @@
/**
* Seed MacroeconomicData and InfrastructureProject tables.
*
* MacroeconomicData: 50+ rows — HCMC & Hanoi, quarterly 2023-Q1 → 2025-Q4.
* InfrastructureProject: 15 real projects with coordinates, status, dates, investment.
*/
import { type PrismaClient } from '@prisma/client';
// =============================================================================
// MacroeconomicData — HCMC & Hanoi, quarterly 20232025
// =============================================================================
interface MacroRow {
province: string;
indicator: string;
value: number;
unit: string;
period: string;
source: string;
}
const QUARTERS = [
'2023-Q1', '2023-Q2', '2023-Q3', '2023-Q4',
'2024-Q1', '2024-Q2', '2024-Q3', '2024-Q4',
'2025-Q1', '2025-Q2', '2025-Q3', '2025-Q4',
];
/**
* Helper: generate quarterly series with a base value and per-quarter growth.
*/
function quarterlySeries(
province: string,
indicator: string,
unit: string,
source: string,
baseValue: number,
quarterlyGrowth: number,
): MacroRow[] {
return QUARTERS.map((period, i) => ({
province,
indicator,
value: Math.round((baseValue + baseValue * quarterlyGrowth * i) * 100) / 100,
unit,
period,
source,
}));
}
function buildMacroData(): MacroRow[] {
const rows: MacroRow[] = [];
// ── Hồ Chí Minh ──────────────────────────────────────────
// GDP growth (% YoY per quarter)
const hcmcGdpGrowth = [5.8, 6.1, 6.4, 6.7, 6.2, 6.5, 6.8, 7.1, 6.9, 7.2, 7.0, 7.3];
QUARTERS.forEach((q, i) => rows.push({ province: 'Hồ Chí Minh', indicator: 'gdp_growth', value: hcmcGdpGrowth[i]!, unit: '%', period: q, source: 'GSO' }));
// CPI (% YoY)
const hcmcCpi = [3.1, 3.3, 3.5, 3.8, 4.0, 3.9, 4.1, 4.2, 3.8, 3.6, 3.5, 3.4];
QUARTERS.forEach((q, i) => rows.push({ province: 'Hồ Chí Minh', indicator: 'cpi', value: hcmcCpi[i]!, unit: '%', period: q, source: 'GSO' }));
// Population (persons, grows slowly)
rows.push(...quarterlySeries('Hồ Chí Minh', 'population', 'người', 'GSO', 9_800_000, 0.003));
// Construction permits (number per quarter)
const hcmcPermits = [1250, 1380, 1420, 1510, 1320, 1460, 1550, 1620, 1480, 1590, 1650, 1720];
QUARTERS.forEach((q, i) => rows.push({ province: 'Hồ Chí Minh', indicator: 'construction_permits', value: hcmcPermits[i]!, unit: 'giấy phép', period: q, source: 'Sở Xây dựng TP.HCM' }));
// FDI (million USD per quarter)
const hcmcFdi = [1650, 1800, 1920, 2050, 1780, 1950, 2100, 2200, 1900, 2080, 2150, 2300];
QUARTERS.forEach((q, i) => rows.push({ province: 'Hồ Chí Minh', indicator: 'fdi', value: hcmcFdi[i]!, unit: 'triệu USD', period: q, source: 'GSO' }));
// RE transaction volume (number of transactions per quarter)
const hcmcTxVol = [8500, 9200, 10100, 11500, 9800, 10500, 11200, 12800, 10200, 11000, 11800, 13500];
QUARTERS.forEach((q, i) => rows.push({ province: 'Hồ Chí Minh', indicator: 're_transaction_volume', value: hcmcTxVol[i]!, unit: 'giao dịch', period: q, source: 'Sở Xây dựng TP.HCM' }));
// ── Hà Nội ────────────────────────────────────────────────
// GDP growth
const hanoiGdpGrowth = [5.2, 5.5, 5.8, 6.0, 5.9, 6.2, 6.5, 6.8, 6.4, 6.7, 6.9, 7.1];
QUARTERS.forEach((q, i) => rows.push({ province: 'Hà Nội', indicator: 'gdp_growth', value: hanoiGdpGrowth[i]!, unit: '%', period: q, source: 'GSO' }));
// CPI
const hanoiCpi = [2.8, 3.0, 3.2, 3.5, 3.7, 3.6, 3.8, 3.9, 3.5, 3.3, 3.2, 3.1];
QUARTERS.forEach((q, i) => rows.push({ province: 'Hà Nội', indicator: 'cpi', value: hanoiCpi[i]!, unit: '%', period: q, source: 'GSO' }));
// Population
rows.push(...quarterlySeries('Hà Nội', 'population', 'người', 'GSO', 8_400_000, 0.0025));
// Construction permits
const hanoiPermits = [980, 1050, 1120, 1200, 1060, 1150, 1230, 1310, 1180, 1260, 1340, 1420];
QUARTERS.forEach((q, i) => rows.push({ province: 'Hà Nội', indicator: 'construction_permits', value: hanoiPermits[i]!, unit: 'giấy phép', period: q, source: 'Sở Xây dựng Hà Nội' }));
// FDI
const hanoiFdi = [1400, 1520, 1650, 1750, 1500, 1620, 1780, 1850, 1600, 1730, 1820, 1950];
QUARTERS.forEach((q, i) => rows.push({ province: 'Hà Nội', indicator: 'fdi', value: hanoiFdi[i]!, unit: 'triệu USD', period: q, source: 'GSO' }));
// RE transaction volume
const hanoiTxVol = [7200, 7800, 8500, 9600, 8100, 8800, 9500, 10800, 8600, 9300, 10000, 11200];
QUARTERS.forEach((q, i) => rows.push({ province: 'Hà Nội', indicator: 're_transaction_volume', value: hanoiTxVol[i]!, unit: 'giao dịch', period: q, source: 'Sở Xây dựng Hà Nội' }));
return rows;
}
// =============================================================================
// InfrastructureProject — 15 real projects with coordinates
// =============================================================================
interface InfraRow {
name: string;
province: string;
category: string;
status: string;
investmentVND: bigint;
startDate: Date | null;
completionDate: Date | null;
description: string;
impactRadius: number;
lat: number;
lng: number;
}
function buildInfraProjects(): InfraRow[] {
return [
// 1. Metro Line 1 (Bến Thành Suối Tiên)
{
name: 'Metro Bến Thành Suối Tiên (Tuyến 1)',
province: 'Hồ Chí Minh',
category: 'metro',
status: 'completed',
investmentVND: BigInt(43_700_000_000_000),
startDate: new Date('2012-08-28'),
completionDate: new Date('2024-12-22'),
description: 'Tuyến metro đầu tiên TP.HCM, 19.7km, 14 ga. Kết nối Quận 1 Thủ Đức Bình Dương.',
impactRadius: 3.0,
lat: 10.7721,
lng: 106.6980,
},
// 2. Metro Line 2 (Bến Thành Tham Lương)
{
name: 'Metro Bến Thành Tham Lương (Tuyến 2)',
province: 'Hồ Chí Minh',
category: 'metro',
status: 'planning',
investmentVND: BigInt(47_800_000_000_000),
startDate: new Date('2026-06-01'),
completionDate: new Date('2032-12-01'),
description: 'Tuyến metro số 2, 11.3km, 10 ga. Kết nối trung tâm đến Tân Bình, Q12.',
impactRadius: 2.5,
lat: 10.7731,
lng: 106.6930,
},
// 3. Thu Duc Innovation District (Khu đô thị sáng tạo Thủ Đức)
{
name: 'Khu Đô thị Sáng tạo Tương tác cao phía Đông (Thủ Đức)',
province: 'Hồ Chí Minh',
category: 'urban_development',
status: 'under_construction',
investmentVND: BigInt(300_000_000_000_000),
startDate: new Date('2020-01-01'),
completionDate: new Date('2040-12-01'),
description: 'Siêu dự án đô thị sáng tạo 21,172ha tại TP. Thủ Đức, gồm khu công nghệ cao, tài chính, giáo dục.',
impactRadius: 10.0,
lat: 10.8231,
lng: 106.7620,
},
// 4. Ring Road 3 (Vành đai 3 TP.HCM)
{
name: 'Đường Vành đai 3 TP.HCM',
province: 'Hồ Chí Minh',
category: 'highway',
status: 'under_construction',
investmentVND: BigInt(75_400_000_000_000),
startDate: new Date('2023-06-18'),
completionDate: new Date('2026-12-01'),
description: 'Tuyến vành đai 76km qua TP.HCM, Bình Dương, Đồng Nai, Long An. 4-8 làn xe.',
impactRadius: 5.0,
lat: 10.8500,
lng: 106.7800,
},
// 5. Long Thanh International Airport — Phase 1
{
name: 'Cảng Hàng không Quốc tế Long Thành Giai đoạn 1',
province: 'Đồng Nai',
category: 'airport',
status: 'under_construction',
investmentVND: BigInt(109_000_000_000_000),
startDate: new Date('2021-01-05'),
completionDate: new Date('2026-12-01'),
description: 'Sân bay quốc tế mới, công suất 25 triệu HK/năm (GĐ1), 100 triệu HK/năm (hoàn thành).',
impactRadius: 15.0,
lat: 10.9730,
lng: 107.0070,
},
// 6. Can Gio Bridge (Cầu Cần Giờ)
{
name: 'Cầu Cần Giờ',
province: 'Hồ Chí Minh',
category: 'bridge',
status: 'planning',
investmentVND: BigInt(10_000_000_000_000),
startDate: new Date('2025-12-01'),
completionDate: new Date('2028-12-01'),
description: 'Cầu dây văng nối Nhà Bè Cần Giờ, dài ~3.4km, rộng 6 làn xe. Mở khóa tiềm năng du lịch & BĐS Cần Giờ.',
impactRadius: 8.0,
lat: 10.6190,
lng: 106.7530,
},
// 7. Cao tốc TP.HCM Long Thành Dầu Giây (mở rộng)
{
name: 'Cao tốc TP.HCM Long Thành Dầu Giây (mở rộng)',
province: 'Hồ Chí Minh',
category: 'highway',
status: 'under_construction',
investmentVND: BigInt(9_000_000_000_000),
startDate: new Date('2024-03-01'),
completionDate: new Date('2027-06-01'),
description: 'Mở rộng từ 4 lên 8-10 làn xe, 55km. Giảm ùn tắc kết nối sân bay Long Thành.',
impactRadius: 4.0,
lat: 10.8350,
lng: 106.8600,
},
// 8. Cao tốc Bến Lức Long Thành
{
name: 'Cao tốc Bến Lức Long Thành',
province: 'Đồng Nai',
category: 'highway',
status: 'under_construction',
investmentVND: BigInt(31_300_000_000_000),
startDate: new Date('2014-07-01'),
completionDate: new Date('2026-09-01'),
description: 'Tuyến cao tốc 57.8km kết nối Long An TP.HCM Đồng Nai, vượt sông Sài Gòn.',
impactRadius: 5.0,
lat: 10.7200,
lng: 106.8500,
},
// 9. Metro Line 3 Hà Nội (Nhổn Ga Hà Nội)
{
name: 'Metro Nhổn Ga Hà Nội (Tuyến 3)',
province: 'Hà Nội',
category: 'metro',
status: 'under_construction',
investmentVND: BigInt(34_800_000_000_000),
startDate: new Date('2010-09-01'),
completionDate: new Date('2027-12-01'),
description: 'Tuyến metro 12.5km, 12 ga, kết nối Nhổn Cầu Giấy ga Hà Nội.',
impactRadius: 2.5,
lat: 21.0285,
lng: 105.8542,
},
// 10. Metro Line 2A Hà Nội (Cát Linh Hà Đông)
{
name: 'Metro Cát Linh Hà Đông (Tuyến 2A)',
province: 'Hà Nội',
category: 'metro',
status: 'completed',
investmentVND: BigInt(18_000_000_000_000),
startDate: new Date('2011-10-10'),
completionDate: new Date('2021-11-06'),
description: 'Tuyến đường sắt trên cao đầu tiên Hà Nội, 13.1km, 12 ga.',
impactRadius: 2.0,
lat: 21.0033,
lng: 105.8245,
},
// 11. Vành đai 4 Hà Nội
{
name: 'Đường Vành đai 4 Vùng Thủ đô Hà Nội',
province: 'Hà Nội',
category: 'highway',
status: 'under_construction',
investmentVND: BigInt(85_800_000_000_000),
startDate: new Date('2023-06-25'),
completionDate: new Date('2027-12-01'),
description: 'Tuyến vành đai 112km qua Hà Nội, Hưng Yên, Bắc Ninh. 6 làn cao tốc.',
impactRadius: 6.0,
lat: 21.0500,
lng: 105.9000,
},
// 12. Sân bay Tân Sơn Nhất Nhà ga T3
{
name: 'Nhà ga T3 Sân bay Tân Sơn Nhất',
province: 'Hồ Chí Minh',
category: 'airport',
status: 'under_construction',
investmentVND: BigInt(10_990_000_000_000),
startDate: new Date('2022-12-01'),
completionDate: new Date('2025-04-30'),
description: 'Nhà ga hành khách T3, công suất 20 triệu HK/năm, nâng tổng công suất TSN lên 50 triệu.',
impactRadius: 5.0,
lat: 10.8188,
lng: 106.6590,
},
// 13. Cảng trung chuyển quốc tế Cần Giờ
{
name: 'Cảng Trung chuyển Quốc tế Cần Giờ',
province: 'Hồ Chí Minh',
category: 'port',
status: 'planning',
investmentVND: BigInt(113_000_000_000_000),
startDate: new Date('2025-06-01'),
completionDate: new Date('2035-12-01'),
description: 'Siêu cảng trung chuyển container quốc tế tại Cần Giờ, công suất 10-15 triệu TEU/năm.',
impactRadius: 12.0,
lat: 10.4110,
lng: 106.9480,
},
// 14. Đường sắt tốc độ cao Bắc Nam (GĐ1)
{
name: 'Đường sắt Tốc độ cao Bắc Nam (Giai đoạn 1)',
province: 'Hà Nội',
category: 'railway',
status: 'planning',
investmentVND: BigInt(670_000_000_000_000),
startDate: new Date('2027-01-01'),
completionDate: new Date('2035-12-01'),
description: 'Đoạn Hà Nội Vinh & Nha Trang TP.HCM, tốc độ thiết kế 350km/h.',
impactRadius: 10.0,
lat: 21.0028,
lng: 105.8440,
},
// 15. Cao tốc Mỹ Phước Tân Vạn (mở rộng)
{
name: 'Cao tốc Mỹ Phước Tân Vạn (mở rộng)',
province: 'Bình Dương',
category: 'highway',
status: 'under_construction',
investmentVND: BigInt(4_500_000_000_000),
startDate: new Date('2023-09-01'),
completionDate: new Date('2026-06-01'),
description: 'Mở rộng kết nối các KCN Bình Dương với TP.HCM, từ 4 lên 8 làn xe.',
impactRadius: 3.0,
lat: 10.9800,
lng: 106.6530,
},
];
}
// =============================================================================
// Public seed function
// =============================================================================
export async function seedMacroAndInfra(prisma: PrismaClient) {
console.log('📈 Seeding macroeconomic data...');
const macroData = buildMacroData();
for (const d of macroData) {
await prisma.macroeconomicData.upsert({
where: {
province_indicator_period: {
province: d.province,
indicator: d.indicator,
period: d.period,
},
},
create: d,
update: { value: d.value, unit: d.unit, source: d.source },
});
}
console.log(`${macroData.length} macroeconomic data points seeded (HCMC + Hanoi, quarterly 20232025)`);
console.log('🏗️ Seeding infrastructure projects...');
const infraProjects = buildInfraProjects();
for (const p of infraProjects) {
const existing = await prisma.infrastructureProject.findFirst({
where: { name: p.name, province: p.province },
});
if (existing) {
// Update existing record with coordinates and dates if missing
await prisma.$executeRaw`
UPDATE "InfrastructureProject"
SET "status" = ${p.status},
"investmentVND" = ${p.investmentVND},
"startDate" = ${p.startDate},
"completionDate" = ${p.completionDate},
"description" = ${p.description},
"impactRadius" = ${p.impactRadius},
"location" = ST_SetSRID(ST_MakePoint(${p.lng}, ${p.lat}), 4326),
"updatedAt" = NOW()
WHERE "id" = ${existing.id}
`;
} else {
await prisma.$executeRaw`
INSERT INTO "InfrastructureProject" (
"id", "name", "province", "category", "status",
"investmentVND", "startDate", "completionDate",
"description", "impactRadius", "location",
"createdAt", "updatedAt"
) VALUES (
gen_random_uuid(), ${p.name}, ${p.province}, ${p.category}, ${p.status},
${p.investmentVND}, ${p.startDate}, ${p.completionDate},
${p.description}, ${p.impactRadius},
ST_SetSRID(ST_MakePoint(${p.lng}, ${p.lat}), 4326),
NOW(), NOW()
)
`;
}
}
console.log(`${infraProjects.length} infrastructure projects seeded (with coordinates)`);
}